]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/ext4/super.c
Merge remote-tracking branch 'l2-mtd/master'
[karo-tx-linux.git] / fs / ext4 / super.c
index 43c0cc802189f89333e353bd7a5bf4257f1d57fc..04d0f1b334096525030674c6d818e124a1bd81f3 100644 (file)
@@ -110,8 +110,7 @@ MODULE_ALIAS("ext3");
 static int ext4_verify_csum_type(struct super_block *sb,
                                 struct ext4_super_block *es)
 {
-       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+       if (!ext4_has_feature_metadata_csum(sb))
                return 1;
 
        return es->s_checksum_type == EXT4_CRC32C_CHKSUM;
@@ -389,9 +388,13 @@ static void ext4_handle_error(struct super_block *sb)
                smp_wmb();
                sb->s_flags |= MS_RDONLY;
        }
-       if (test_opt(sb, ERRORS_PANIC))
+       if (test_opt(sb, ERRORS_PANIC)) {
+               if (EXT4_SB(sb)->s_journal &&
+                 !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
+                       return;
                panic("EXT4-fs (device %s): panic forced after error\n",
                        sb->s_id);
+       }
 }
 
 #define ext4_error_ratelimit(sb)                                       \
@@ -490,6 +493,12 @@ const char *ext4_decode_error(struct super_block *sb, int errno,
        char *errstr = NULL;
 
        switch (errno) {
+       case -EFSCORRUPTED:
+               errstr = "Corrupt filesystem";
+               break;
+       case -EFSBADCRC:
+               errstr = "Filesystem failed CRC";
+               break;
        case -EIO:
                errstr = "IO failure";
                break;
@@ -580,8 +589,12 @@ void __ext4_abort(struct super_block *sb, const char *function,
                        jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
                save_error_info(sb, function, line);
        }
-       if (test_opt(sb, ERRORS_PANIC))
+       if (test_opt(sb, ERRORS_PANIC)) {
+               if (EXT4_SB(sb)->s_journal &&
+                 !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
+                       return;
                panic("EXT4-fs panic from previous error\n");
+       }
 }
 
 void __ext4_msg(struct super_block *sb,
@@ -804,7 +817,7 @@ static void ext4_put_super(struct super_block *sb)
        ext4_xattr_put_super(sb);
 
        if (!(sb->s_flags & MS_RDONLY)) {
-               EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_clear_feature_journal_needs_recovery(sb);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
        }
        if (!(sb->s_flags & MS_RDONLY))
@@ -1278,7 +1291,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
                        "quota options when quota turned on");
                return -1;
        }
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+       if (ext4_has_feature_quota(sb)) {
                ext4_msg(sb, KERN_ERR, "Cannot set journaled quota options "
                         "when QUOTA feature is enabled");
                return -1;
@@ -1371,10 +1384,10 @@ static const struct mount_opts {
        {Opt_nojournal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
         MOPT_EXT4_ONLY | MOPT_CLEAR},
        {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
-        MOPT_EXT4_ONLY | MOPT_SET},
+        MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
        {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
                                    EXT4_MOUNT_JOURNAL_CHECKSUM),
-        MOPT_EXT4_ONLY | MOPT_SET},
+        MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
        {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_NO_EXT2 | MOPT_SET},
        {Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR},
        {Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR},
@@ -1503,8 +1516,14 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                return -1;
        if (args->from && (m->flags & MOPT_GTE0) && (arg < 0))
                return -1;
-       if (m->flags & MOPT_EXPLICIT)
-               set_opt2(sb, EXPLICIT_DELALLOC);
+       if (m->flags & MOPT_EXPLICIT) {
+               if (m->mount_opt & EXT4_MOUNT_DELALLOC) {
+                       set_opt2(sb, EXPLICIT_DELALLOC);
+               } else if (m->mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) {
+                       set_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM);
+               } else
+                       return -1;
+       }
        if (m->flags & MOPT_CLEAR_ERR)
                clear_opt(sb, ERRORS_MASK);
        if (token == Opt_noquota && sb_any_quota_loaded(sb)) {
@@ -1637,8 +1656,7 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
                                 "quota options when quota turned on");
                        return -1;
                }
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                              EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+               if (ext4_has_feature_quota(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "Cannot set journaled quota options "
                                 "when QUOTA feature is enabled");
@@ -1697,7 +1715,7 @@ static int parse_options(char *options, struct super_block *sb,
                        return 0;
        }
 #ifdef CONFIG_QUOTA
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
+       if (ext4_has_feature_quota(sb) &&
            (test_opt(sb, USRQUOTA) || test_opt(sb, GRPQUOTA))) {
                ext4_msg(sb, KERN_ERR, "Cannot set quota options when QUOTA "
                         "feature is enabled");
@@ -1921,7 +1939,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
        es->s_mtime = cpu_to_le32(get_seconds());
        ext4_update_dynamic_rev(sb);
        if (sbi->s_journal)
-               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_set_feature_journal_needs_recovery(sb);
 
        ext4_commit_super(sb, 1);
 done:
@@ -2004,12 +2022,13 @@ failed:
        return 0;
 }
 
-static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
+static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
                                   struct ext4_group_desc *gdp)
 {
        int offset;
        __u16 crc = 0;
        __le32 le_group = cpu_to_le32(block_group);
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (ext4_has_metadata_csum(sbi->s_sb)) {
                /* Use new metadata_csum algorithm */
@@ -2029,8 +2048,7 @@ static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
        }
 
        /* old crc16 code */
-       if (!(sbi->s_es->s_feature_ro_compat &
-             cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
+       if (!ext4_has_feature_gdt_csum(sb))
                return 0;
 
        offset = offsetof(struct ext4_group_desc, bg_checksum);
@@ -2040,8 +2058,7 @@ static __le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
        crc = crc16(crc, (__u8 *)gdp, offset);
        offset += sizeof(gdp->bg_checksum); /* skip checksum */
        /* for checksum of struct ext4_group_desc do the rest...*/
-       if ((sbi->s_es->s_feature_incompat &
-            cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
+       if (ext4_has_feature_64bit(sb) &&
            offset < le16_to_cpu(sbi->s_es->s_desc_size))
                crc = crc16(crc, (__u8 *)gdp + offset,
                            le16_to_cpu(sbi->s_es->s_desc_size) -
@@ -2055,8 +2072,7 @@ int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group,
                                struct ext4_group_desc *gdp)
 {
        if (ext4_has_group_desc_csum(sb) &&
-           (gdp->bg_checksum != ext4_group_desc_csum(EXT4_SB(sb),
-                                                     block_group, gdp)))
+           (gdp->bg_checksum != ext4_group_desc_csum(sb, block_group, gdp)))
                return 0;
 
        return 1;
@@ -2067,7 +2083,7 @@ void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group,
 {
        if (!ext4_has_group_desc_csum(sb))
                return;
-       gdp->bg_checksum = ext4_group_desc_csum(EXT4_SB(sb), block_group, gdp);
+       gdp->bg_checksum = ext4_group_desc_csum(sb, block_group, gdp);
 }
 
 /* Called at mount-time, super-block is locked */
@@ -2083,7 +2099,7 @@ static int ext4_check_descriptors(struct super_block *sb,
        int flexbg_flag = 0;
        ext4_group_t i, grp = sbi->s_groups_count;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+       if (ext4_has_feature_flex_bg(sb))
                flexbg_flag = 1;
 
        ext4_debug("Checking group descriptors");
@@ -2127,7 +2143,7 @@ static int ext4_check_descriptors(struct super_block *sb,
                if (!ext4_group_desc_csum_verify(sb, i, gdp)) {
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                                 "Checksum for group %u failed (%u!=%u)",
-                                i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
+                                i, le16_to_cpu(ext4_group_desc_csum(sb, i,
                                     gdp)), le16_to_cpu(gdp->bg_checksum));
                        if (!(sb->s_flags & MS_RDONLY)) {
                                ext4_unlock_group(sb, i);
@@ -2390,8 +2406,7 @@ static ext4_fsblk_t descriptor_loc(struct super_block *sb,
 
        first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
 
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
-           nr < first_meta_bg)
+       if (!ext4_has_feature_meta_bg(sb) || nr < first_meta_bg)
                return logical_sb_block + nr + 1;
        bg = sbi->s_desc_per_block * nr;
        if (ext4_bg_has_super(sb, bg))
@@ -2455,7 +2470,7 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
  */
 static int ext4_feature_set_ok(struct super_block *sb, int readonly)
 {
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP)) {
+       if (ext4_has_unknown_ext4_incompat_features(sb)) {
                ext4_msg(sb, KERN_ERR,
                        "Couldn't mount because of "
                        "unsupported optional features (%x)",
@@ -2467,14 +2482,14 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
        if (readonly)
                return 1;
 
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_READONLY)) {
+       if (ext4_has_feature_readonly(sb)) {
                ext4_msg(sb, KERN_INFO, "filesystem is read-only");
                sb->s_flags |= MS_RDONLY;
                return 1;
        }
 
        /* Check that feature set is OK for a read-write mount */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
+       if (ext4_has_unknown_ext4_ro_compat_features(sb)) {
                ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of "
                         "unsupported optional features (%x)",
                         (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) &
@@ -2485,7 +2500,7 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
         * Large file size enabled file system can only be mounted
         * read-write on 32-bit systems if kernel is built with CONFIG_LBDAF
         */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+       if (ext4_has_feature_huge_file(sb)) {
                if (sizeof(blkcnt_t) < sizeof(u64)) {
                        ext4_msg(sb, KERN_ERR, "Filesystem with huge files "
                                 "cannot be mounted RDWR without "
@@ -2493,8 +2508,7 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
                        return 0;
                }
        }
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC) &&
-           !EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+       if (ext4_has_feature_bigalloc(sb) && !ext4_has_feature_extents(sb)) {
                ext4_msg(sb, KERN_ERR,
                         "Can't support bigalloc feature without "
                         "extents feature\n");
@@ -2502,8 +2516,7 @@ static int ext4_feature_set_ok(struct super_block *sb, int readonly)
        }
 
 #ifndef CONFIG_QUOTA
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
-           !readonly) {
+       if (ext4_has_feature_quota(sb) && !readonly) {
                ext4_msg(sb, KERN_ERR,
                         "Filesystem with quota feature cannot be mounted RDWR "
                         "without CONFIG_QUOTA");
@@ -2960,7 +2973,7 @@ static int count_overhead(struct super_block *sb, ext4_group_t grp,
        ext4_group_t            i, ngroups = ext4_get_groups_count(sb);
        int                     s, j, count = 0;
 
-       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC))
+       if (!ext4_has_feature_bigalloc(sb))
                return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) +
                        sbi->s_itb_per_group + 2);
 
@@ -3062,7 +3075,7 @@ static void ext4_set_resv_clusters(struct super_block *sb)
         * hole punching doesn't need new metadata... This is needed especially
         * to keep ext2/3 backward compatibility.
         */
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS))
+       if (!ext4_has_feature_extents(sb))
                return;
        /*
         * By default we reserve 2% or 4096 clusters, whichever is smaller.
@@ -3161,9 +3174,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written);
 
        /* Warn if metadata_csum and gdt_csum are both set. */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
-           EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM))
+       if (ext4_has_feature_metadata_csum(sb) &&
+           ext4_has_feature_gdt_csum(sb))
                ext4_warning(sb, "metadata_csum and uninit_bg are "
                             "redundant flags; please run fsck.");
 
@@ -3176,8 +3188,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* Load the checksum driver */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext4_has_feature_metadata_csum(sb)) {
                sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0);
                if (IS_ERR(sbi->s_chksum_driver)) {
                        ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver.");
@@ -3192,11 +3203,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with "
                         "invalid superblock checksum.  Run e2fsck?");
                silent = 1;
+               ret = -EFSBADCRC;
                goto cantfind_ext4;
        }
 
        /* Precompute checksum seed for all metadata */
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_CSUM_SEED))
+       if (ext4_has_feature_csum_seed(sb))
                sbi->s_csum_seed = le32_to_cpu(es->s_checksum_seed);
        else if (ext4_has_metadata_csum(sb))
                sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid,
@@ -3301,17 +3313,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0);
 
        if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
-           (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
-            EXT4_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
-            EXT4_HAS_INCOMPAT_FEATURE(sb, ~0U)))
+           (ext4_has_compat_features(sb) ||
+            ext4_has_ro_compat_features(sb) ||
+            ext4_has_incompat_features(sb)))
                ext4_msg(sb, KERN_WARNING,
                       "feature flags set on rev 0 fs, "
                       "running e2fsck is recommended");
 
        if (es->s_creator_os == cpu_to_le32(EXT4_OS_HURD)) {
                set_opt2(sb, HURD_COMPAT);
-               if (EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                             EXT4_FEATURE_INCOMPAT_64BIT)) {
+               if (ext4_has_feature_64bit(sb)) {
                        ext4_msg(sb, KERN_ERR,
                                 "The Hurd can't support 64-bit file systems");
                        goto failed_mount;
@@ -3369,8 +3380,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                }
        }
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT) &&
-           es->s_encryption_level) {
+       if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) {
                ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d",
                         es->s_encryption_level);
                goto failed_mount;
@@ -3402,8 +3412,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                }
        }
 
-       has_huge_files = EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
+       has_huge_files = ext4_has_feature_huge_file(sb);
        sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits,
                                                      has_huge_files);
        sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files);
@@ -3427,7 +3436,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        sbi->s_desc_size = le16_to_cpu(es->s_desc_size);
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
+       if (ext4_has_feature_64bit(sb)) {
                if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
                    sbi->s_desc_size > EXT4_MAX_DESC_SIZE ||
                    !is_power_of_2(sbi->s_desc_size)) {
@@ -3458,7 +3467,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        for (i = 0; i < 4; i++)
                sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
        sbi->s_def_hash_version = es->s_def_hash_version;
-       if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+       if (ext4_has_feature_dir_index(sb)) {
                i = le32_to_cpu(es->s_flags);
                if (i & EXT2_FLAGS_UNSIGNED_HASH)
                        sbi->s_hash_unsigned = 3;
@@ -3478,8 +3487,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
 
        /* Handle clustersize */
        clustersize = BLOCK_SIZE << le32_to_cpu(es->s_log_cluster_size);
-       has_bigalloc = EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                               EXT4_FEATURE_RO_COMPAT_BIGALLOC);
+       has_bigalloc = ext4_has_feature_bigalloc(sb);
        if (has_bigalloc) {
                if (clustersize < blocksize) {
                        ext4_msg(sb, KERN_ERR,
@@ -3612,6 +3620,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
        if (!ext4_check_descriptors(sb, &first_not_zeroed)) {
                ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
+               ret = -EFSCORRUPTED;
                goto failed_mount2;
        }
 
@@ -3637,7 +3646,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_xattr = ext4_xattr_handlers;
 #ifdef CONFIG_QUOTA
        sb->dq_op = &ext4_quota_operations;
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA))
+       if (ext4_has_feature_quota(sb))
                sb->s_qcop = &dquot_quotactl_sysfile_ops;
        else
                sb->s_qcop = &ext4_qctl_operations;
@@ -3651,11 +3660,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_root = NULL;
 
        needs_recovery = (es->s_last_orphan != 0 ||
-                         EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                   EXT4_FEATURE_INCOMPAT_RECOVER));
+                         ext4_has_feature_journal_needs_recovery(sb));
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_MMP) &&
-           !(sb->s_flags & MS_RDONLY))
+       if (ext4_has_feature_mmp(sb) && !(sb->s_flags & MS_RDONLY))
                if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
                        goto failed_mount3a;
 
@@ -3663,23 +3670,47 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * The first inode we look at is the journal inode.  Don't try
         * root first: it may be modified in the journal!
         */
-       if (!test_opt(sb, NOLOAD) &&
-           EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
+       if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) {
                if (ext4_load_journal(sb, es, journal_devnum))
                        goto failed_mount3a;
        } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
-             EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
+                  ext4_has_feature_journal_needs_recovery(sb)) {
                ext4_msg(sb, KERN_ERR, "required journal recovery "
                       "suppressed and not mounted read-only");
                goto failed_mount_wq;
        } else {
+               /* Nojournal mode, all journal mount options are illegal */
+               if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "journal_checksum, fs mounted w/o journal");
+                       goto failed_mount_wq;
+               }
+               if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "journal_async_commit, fs mounted w/o journal");
+                       goto failed_mount_wq;
+               }
+               if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "commit=%lu, fs mounted w/o journal",
+                                sbi->s_commit_interval / HZ);
+                       goto failed_mount_wq;
+               }
+               if (EXT4_MOUNT_DATA_FLAGS &
+                   (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) {
+                       ext4_msg(sb, KERN_ERR, "can't mount with "
+                                "data=, fs mounted w/o journal");
+                       goto failed_mount_wq;
+               }
+               sbi->s_def_mount_opt &= EXT4_MOUNT_JOURNAL_CHECKSUM;
+               clear_opt(sb, JOURNAL_CHECKSUM);
                clear_opt(sb, DATA_FLAGS);
                sbi->s_journal = NULL;
                needs_recovery = 0;
                goto no_journal;
        }
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT) &&
+       if (ext4_has_feature_64bit(sb) &&
            !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0,
                                       JBD2_FEATURE_INCOMPAT_64BIT)) {
                ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature");
@@ -3731,18 +3762,16 @@ no_journal:
                }
        }
 
-       if ((DUMMY_ENCRYPTION_ENABLED(sbi) ||
-            EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT)) &&
+       if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) &&
            (blocksize != PAGE_CACHE_SIZE)) {
                ext4_msg(sb, KERN_ERR,
                         "Unsupported blocksize for fs encryption");
                goto failed_mount_wq;
        }
 
-       if (DUMMY_ENCRYPTION_ENABLED(sbi) &&
-           !(sb->s_flags & MS_RDONLY) &&
-           !EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT)) {
-               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_ENCRYPT);
+       if (DUMMY_ENCRYPTION_ENABLED(sbi) && !(sb->s_flags & MS_RDONLY) &&
+           !ext4_has_feature_encrypt(sb)) {
+               ext4_set_feature_encrypt(sb);
                ext4_commit_super(sb, 1);
        }
 
@@ -3801,8 +3830,7 @@ no_journal:
        if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) {
                sbi->s_want_extra_isize = sizeof(struct ext4_inode) -
                                                     EXT4_GOOD_OLD_INODE_SIZE;
-               if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                      EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE)) {
+               if (ext4_has_feature_extra_isize(sb)) {
                        if (sbi->s_want_extra_isize <
                            le16_to_cpu(es->s_want_extra_isize))
                                sbi->s_want_extra_isize =
@@ -3861,7 +3889,7 @@ no_journal:
                goto failed_mount6;
        }
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+       if (ext4_has_feature_flex_bg(sb))
                if (!ext4_fill_flex_info(sb)) {
                        ext4_msg(sb, KERN_ERR,
                               "unable to initialize "
@@ -3879,8 +3907,7 @@ no_journal:
 
 #ifdef CONFIG_QUOTA
        /* Enable quota usage during mount. */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) &&
-           !(sb->s_flags & MS_RDONLY)) {
+       if (ext4_has_feature_quota(sb) && !(sb->s_flags & MS_RDONLY)) {
                err = ext4_enable_quotas(sb);
                if (err)
                        goto failed_mount8;
@@ -4021,7 +4048,7 @@ static journal_t *ext4_get_journal(struct super_block *sb,
        struct inode *journal_inode;
        journal_t *journal;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        /* First, test for the existence of a valid inode on disk.  Bad
         * things happen if we iget() an unused inode, as the subsequent
@@ -4071,7 +4098,7 @@ static journal_t *ext4_get_dev_journal(struct super_block *sb,
        struct ext4_super_block *es;
        struct block_device *bdev;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        bdev = ext4_blkdev_get(j_dev, sb);
        if (bdev == NULL)
@@ -4163,7 +4190,7 @@ static int ext4_load_journal(struct super_block *sb,
        int err = 0;
        int really_read_only;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        if (journal_devnum &&
            journal_devnum != le32_to_cpu(es->s_journal_dev)) {
@@ -4180,7 +4207,7 @@ static int ext4_load_journal(struct super_block *sb,
         * crash?  For recovery, we need to check in advance whether we
         * can get read-write access to the device.
         */
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
+       if (ext4_has_feature_journal_needs_recovery(sb)) {
                if (sb->s_flags & MS_RDONLY) {
                        ext4_msg(sb, KERN_INFO, "INFO: recovery "
                                        "required on readonly filesystem");
@@ -4211,7 +4238,7 @@ static int ext4_load_journal(struct super_block *sb,
        if (!(journal->j_flags & JBD2_BARRIER))
                ext4_msg(sb, KERN_INFO, "barriers disabled");
 
-       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
+       if (!ext4_has_feature_journal_needs_recovery(sb))
                err = jbd2_journal_wipe(journal, !really_read_only);
        if (!err) {
                char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
@@ -4325,7 +4352,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
 {
        journal_t *journal = EXT4_SB(sb)->s_journal;
 
-       if (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
+       if (!ext4_has_feature_journal(sb)) {
                BUG_ON(journal != NULL);
                return;
        }
@@ -4333,9 +4360,9 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
        if (jbd2_journal_flush(journal) < 0)
                goto out;
 
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
+       if (ext4_has_feature_journal_needs_recovery(sb) &&
            sb->s_flags & MS_RDONLY) {
-               EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_clear_feature_journal_needs_recovery(sb);
                ext4_commit_super(sb, 1);
        }
 
@@ -4355,7 +4382,7 @@ static void ext4_clear_journal_err(struct super_block *sb,
        int j_errno;
        const char *errstr;
 
-       BUG_ON(!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL));
+       BUG_ON(!ext4_has_feature_journal(sb));
 
        journal = EXT4_SB(sb)->s_journal;
 
@@ -4470,7 +4497,7 @@ static int ext4_freeze(struct super_block *sb)
                        goto out;
 
                /* Journal blocked and flushed, clear needs_recovery flag. */
-               EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_clear_feature_journal_needs_recovery(sb);
        }
 
        error = ext4_commit_super(sb, 1);
@@ -4492,7 +4519,7 @@ static int ext4_unfreeze(struct super_block *sb)
 
        if (EXT4_SB(sb)->s_journal) {
                /* Reset the needs_recovery flag before the fs is unlocked. */
-               EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+               ext4_set_feature_journal_needs_recovery(sb);
        }
 
        ext4_commit_super(sb, 1);
@@ -4645,8 +4672,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                ext4_mark_recovery_complete(sb, es);
                } else {
                        /* Make sure we can mount this feature set readwrite */
-                       if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_READONLY) ||
+                       if (ext4_has_feature_readonly(sb) ||
                            !ext4_feature_set_ok(sb, 0)) {
                                err = -EROFS;
                                goto restore_opts;
@@ -4662,9 +4688,9 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                                if (!ext4_group_desc_csum_verify(sb, g, gdp)) {
                                        ext4_msg(sb, KERN_ERR,
               "ext4_remount: Checksum for group %u failed (%u!=%u)",
-               g, le16_to_cpu(ext4_group_desc_csum(sbi, g, gdp)),
+               g, le16_to_cpu(ext4_group_desc_csum(sb, g, gdp)),
                                               le16_to_cpu(gdp->bg_checksum));
-                                       err = -EINVAL;
+                                       err = -EFSBADCRC;
                                        goto restore_opts;
                                }
                        }
@@ -4694,8 +4720,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                        sbi->s_mount_state = le16_to_cpu(es->s_state);
                        if (!ext4_setup_super(sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
-                       if (EXT4_HAS_INCOMPAT_FEATURE(sb,
-                                                    EXT4_FEATURE_INCOMPAT_MMP))
+                       if (ext4_has_feature_mmp(sb))
                                if (ext4_multi_mount_protect(sb,
                                                le64_to_cpu(es->s_mmp_block))) {
                                        err = -EROFS;
@@ -4728,8 +4753,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        if (enable_quota) {
                if (sb_any_quota_suspended(sb))
                        dquot_resume(sb, -1);
-               else if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
-                                       EXT4_FEATURE_RO_COMPAT_QUOTA)) {
+               else if (ext4_has_feature_quota(sb)) {
                        err = ext4_enable_quotas(sb);
                        if (err)
                                goto restore_opts;
@@ -4873,7 +4897,7 @@ static int ext4_mark_dquot_dirty(struct dquot *dquot)
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        /* Are we journaling quotas? */
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA) ||
+       if (ext4_has_feature_quota(sb) ||
            sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
                dquot_mark_dquot_dirty(dquot);
                return ext4_write_dquot(dquot);
@@ -4961,7 +4985,7 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
                le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum)
        };
 
-       BUG_ON(!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_QUOTA));
+       BUG_ON(!ext4_has_feature_quota(sb));
 
        if (!qf_inums[type])
                return -EPERM;
@@ -5155,11 +5179,11 @@ static inline void unregister_as_ext2(void)
 
 static inline int ext2_feature_set_ok(struct super_block *sb)
 {
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT2_FEATURE_INCOMPAT_SUPP))
+       if (ext4_has_unknown_ext2_incompat_features(sb))
                return 0;
        if (sb->s_flags & MS_RDONLY)
                return 1;
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP))
+       if (ext4_has_unknown_ext2_ro_compat_features(sb))
                return 0;
        return 1;
 }
@@ -5184,13 +5208,13 @@ static inline void unregister_as_ext3(void)
 
 static inline int ext3_feature_set_ok(struct super_block *sb)
 {
-       if (EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP))
+       if (ext4_has_unknown_ext3_incompat_features(sb))
                return 0;
-       if (!EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL))
+       if (!ext4_has_feature_journal(sb))
                return 0;
        if (sb->s_flags & MS_RDONLY)
                return 1;
-       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP))
+       if (ext4_has_unknown_ext3_ro_compat_features(sb))
                return 0;
        return 1;
 }