aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/super.c55
-rw-r--r--fs/jbd2/journal.c50
2 files changed, 92 insertions, 13 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 88c2054fb938..8dfb42e380ea 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -3013,6 +3013,44 @@ static void ext4_destroy_lazyinit_thread(void)
3013 kthread_stop(ext4_lazyinit_task); 3013 kthread_stop(ext4_lazyinit_task);
3014} 3014}
3015 3015
3016static int set_journal_csum_feature_set(struct super_block *sb)
3017{
3018 int ret = 1;
3019 int compat, incompat;
3020 struct ext4_sb_info *sbi = EXT4_SB(sb);
3021
3022 if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
3023 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
3024 /* journal checksum v2 */
3025 compat = 0;
3026 incompat = JBD2_FEATURE_INCOMPAT_CSUM_V2;
3027 } else {
3028 /* journal checksum v1 */
3029 compat = JBD2_FEATURE_COMPAT_CHECKSUM;
3030 incompat = 0;
3031 }
3032
3033 if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
3034 ret = jbd2_journal_set_features(sbi->s_journal,
3035 compat, 0,
3036 JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT |
3037 incompat);
3038 } else if (test_opt(sb, JOURNAL_CHECKSUM)) {
3039 ret = jbd2_journal_set_features(sbi->s_journal,
3040 compat, 0,
3041 incompat);
3042 jbd2_journal_clear_features(sbi->s_journal, 0, 0,
3043 JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
3044 } else {
3045 jbd2_journal_clear_features(sbi->s_journal,
3046 JBD2_FEATURE_COMPAT_CHECKSUM, 0,
3047 JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT |
3048 JBD2_FEATURE_INCOMPAT_CSUM_V2);
3049 }
3050
3051 return ret;
3052}
3053
3016static int ext4_fill_super(struct super_block *sb, void *data, int silent) 3054static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3017{ 3055{
3018 char *orig_data = kstrdup(data, GFP_KERNEL); 3056 char *orig_data = kstrdup(data, GFP_KERNEL);
@@ -3610,19 +3648,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
3610 goto failed_mount_wq; 3648 goto failed_mount_wq;
3611 } 3649 }
3612 3650
3613 if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { 3651 if (!set_journal_csum_feature_set(sb)) {
3614 jbd2_journal_set_features(sbi->s_journal, 3652 ext4_msg(sb, KERN_ERR, "Failed to set journal checksum "
3615 JBD2_FEATURE_COMPAT_CHECKSUM, 0, 3653 "feature set");
3616 JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); 3654 goto failed_mount_wq;
3617 } else if (test_opt(sb, JOURNAL_CHECKSUM)) {
3618 jbd2_journal_set_features(sbi->s_journal,
3619 JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0);
3620 jbd2_journal_clear_features(sbi->s_journal, 0, 0,
3621 JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
3622 } else {
3623 jbd2_journal_clear_features(sbi->s_journal,
3624 JBD2_FEATURE_COMPAT_CHECKSUM, 0,
3625 JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
3626 } 3655 }
3627 3656
3628 /* We have now updated the journal if required, so we can 3657 /* We have now updated the journal if required, so we can
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 1afb701622b0..63175f9391ab 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -97,6 +97,15 @@ EXPORT_SYMBOL(jbd2_inode_cache);
97static void __journal_abort_soft (journal_t *journal, int errno); 97static void __journal_abort_soft (journal_t *journal, int errno);
98static int jbd2_journal_create_slab(size_t slab_size); 98static int jbd2_journal_create_slab(size_t slab_size);
99 99
100/* Checksumming functions */
101int 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
100/* 109/*
101 * Helper function used to manage commit timeouts 110 * Helper function used to manage commit timeouts
102 */ 111 */
@@ -1376,6 +1385,9 @@ static int journal_get_superblock(journal_t *journal)
1376 } 1385 }
1377 } 1386 }
1378 1387
1388 if (buffer_verified(bh))
1389 return 0;
1390
1379 sb = journal->j_superblock; 1391 sb = journal->j_superblock;
1380 1392
1381 err = -EINVAL; 1393 err = -EINVAL;
@@ -1413,6 +1425,21 @@ static int journal_get_superblock(journal_t *journal)
1413 goto out; 1425 goto out;
1414 } 1426 }
1415 1427
1428 if (JBD2_HAS_COMPAT_FEATURE(journal, JBD2_FEATURE_COMPAT_CHECKSUM) &&
1429 JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_CSUM_V2)) {
1430 /* Can't have checksum v1 and v2 on at the same time! */
1431 printk(KERN_ERR "JBD: Can't enable checksumming v1 and v2 "
1432 "at the same time!\n");
1433 goto out;
1434 }
1435
1436 if (!jbd2_verify_csum_type(journal, sb)) {
1437 printk(KERN_ERR "JBD: Unknown checksum type\n");
1438 goto out;
1439 }
1440
1441 set_buffer_verified(bh);
1442
1416 return 0; 1443 return 0;
1417 1444
1418out: 1445out:
@@ -1653,6 +1680,10 @@ int jbd2_journal_check_available_features (journal_t *journal, unsigned long com
1653int jbd2_journal_set_features (journal_t *journal, unsigned long compat, 1680int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
1654 unsigned long ro, unsigned long incompat) 1681 unsigned long ro, unsigned long incompat)
1655{ 1682{
1683#define INCOMPAT_FEATURE_ON(f) \
1684 ((incompat & (f)) && !(sb->s_feature_incompat & cpu_to_be32(f)))
1685#define COMPAT_FEATURE_ON(f) \
1686 ((compat & (f)) && !(sb->s_feature_compat & cpu_to_be32(f)))
1656 journal_superblock_t *sb; 1687 journal_superblock_t *sb;
1657 1688
1658 if (jbd2_journal_check_used_features(journal, compat, ro, incompat)) 1689 if (jbd2_journal_check_used_features(journal, compat, ro, incompat))
@@ -1661,16 +1692,35 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
1661 if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) 1692 if (!jbd2_journal_check_available_features(journal, compat, ro, incompat))
1662 return 0; 1693 return 0;
1663 1694
1695 /* Asking for checksumming v2 and v1? Only give them v2. */
1696 if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2 &&
1697 compat & JBD2_FEATURE_COMPAT_CHECKSUM)
1698 compat &= ~JBD2_FEATURE_COMPAT_CHECKSUM;
1699
1664 jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", 1700 jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n",
1665 compat, ro, incompat); 1701 compat, ro, incompat);
1666 1702
1667 sb = journal->j_superblock; 1703 sb = journal->j_superblock;
1668 1704
1705 /* If enabling v2 checksums, update superblock */
1706 if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V2)) {
1707 sb->s_checksum_type = JBD2_CRC32C_CHKSUM;
1708 sb->s_feature_compat &=
1709 ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM);
1710 }
1711
1712 /* If enabling v1 checksums, downgrade superblock */
1713 if (COMPAT_FEATURE_ON(JBD2_FEATURE_COMPAT_CHECKSUM))
1714 sb->s_feature_incompat &=
1715 ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2);
1716
1669 sb->s_feature_compat |= cpu_to_be32(compat); 1717 sb->s_feature_compat |= cpu_to_be32(compat);
1670 sb->s_feature_ro_compat |= cpu_to_be32(ro); 1718 sb->s_feature_ro_compat |= cpu_to_be32(ro);
1671 sb->s_feature_incompat |= cpu_to_be32(incompat); 1719 sb->s_feature_incompat |= cpu_to_be32(incompat);
1672 1720
1673 return 1; 1721 return 1;
1722#undef COMPAT_FEATURE_ON
1723#undef INCOMPAT_FEATURE_ON
1674} 1724}
1675 1725
1676/* 1726/*