]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - fs/ext4/super.c
VFS: Convert sb->s_flags & MS_RDONLY to sb_rdonly(sb)
[mirror_ubuntu-bionic-kernel.git] / fs / ext4 / super.c
index 9006cb5857b802e301fa5923feafb8a3e87db884..d9701c869dd38179d742fdddef94cd9545c48bb0 100644 (file)
@@ -373,6 +373,9 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
        struct ext4_journal_cb_entry    *jce;
 
        BUG_ON(txn->t_state == T_FINISHED);
+
+       ext4_process_freed_data(sb, txn->t_tid);
+
        spin_lock(&sbi->s_md_lock);
        while (!list_empty(&txn->t_private_list)) {
                jce = list_entry(txn->t_private_list.next,
@@ -402,7 +405,7 @@ static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn)
 
 static void ext4_handle_error(struct super_block *sb)
 {
-       if (sb->s_flags & MS_RDONLY)
+       if (sb_rdonly(sb))
                return;
 
        if (!test_opt(sb, ERRORS_CONT)) {
@@ -584,8 +587,7 @@ void __ext4_std_error(struct super_block *sb, const char *function,
        /* Special case: if the error is EROFS, and we're not already
         * inside a transaction, then there's really no point in logging
         * an error. */
-       if (errno == -EROFS && journal_current_handle() == NULL &&
-           (sb->s_flags & MS_RDONLY))
+       if (errno == -EROFS && journal_current_handle() == NULL && sb_rdonly(sb))
                return;
 
        if (ext4_error_ratelimit(sb)) {
@@ -625,7 +627,7 @@ void __ext4_abort(struct super_block *sb, const char *function,
               sb->s_id, function, line, &vaf);
        va_end(args);
 
-       if ((sb->s_flags & MS_RDONLY) == 0) {
+       if (sb_rdonly(sb) == 0) {
                ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
                EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
                /*
@@ -886,11 +888,11 @@ static void ext4_put_super(struct super_block *sb)
        ext4_mb_release(sb);
        ext4_ext_release(sb);
 
-       if (!(sb->s_flags & MS_RDONLY) && !aborted) {
+       if (!sb_rdonly(sb) && !aborted) {
                ext4_clear_feature_journal_needs_recovery(sb);
                es->s_state = cpu_to_le16(sbi->s_mount_state);
        }
-       if (!(sb->s_flags & MS_RDONLY))
+       if (!sb_rdonly(sb))
                ext4_commit_super(sb, 1);
 
        for (i = 0; i < sbi->s_gdb_count; i++)
@@ -927,9 +929,13 @@ static void ext4_put_super(struct super_block *sb)
                invalidate_bdev(sbi->journal_bdev);
                ext4_blkdev_remove(sbi);
        }
-       if (sbi->s_mb_cache) {
-               ext4_xattr_destroy_cache(sbi->s_mb_cache);
-               sbi->s_mb_cache = NULL;
+       if (sbi->s_ea_inode_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
+               sbi->s_ea_inode_cache = NULL;
+       }
+       if (sbi->s_ea_block_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
+               sbi->s_ea_block_cache = NULL;
        }
        if (sbi->s_mmp_tsk)
                kthread_stop(sbi->s_mmp_tsk);
@@ -1143,7 +1149,16 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
                                                        void *fs_data)
 {
        handle_t *handle = fs_data;
-       int res, res2, retries = 0;
+       int res, res2, credits, retries = 0;
+
+       /*
+        * Encrypting the root directory is not allowed because e2fsck expects
+        * lost+found to exist and be unencrypted, and encrypting the root
+        * directory would imply encrypting the lost+found directory as well as
+        * the filename "lost+found" itself.
+        */
+       if (inode->i_ino == EXT4_ROOT_INO)
+               return -EPERM;
 
        res = ext4_convert_inline_data(inode);
        if (res)
@@ -1178,8 +1193,12 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
        if (res)
                return res;
 retry:
-       handle = ext4_journal_start(inode, EXT4_HT_MISC,
-                       ext4_jbd2_credits_xattr(inode));
+       res = ext4_xattr_set_credits(inode, len, false /* is_create */,
+                                    &credits);
+       if (res)
+               return res;
+
+       handle = ext4_journal_start(inode, EXT4_HT_MISC, credits);
        if (IS_ERR(handle))
                return PTR_ERR(handle);
 
@@ -1203,7 +1222,7 @@ retry:
        return res;
 }
 
-static int ext4_dummy_context(struct inode *inode)
+static bool ext4_dummy_context(struct inode *inode)
 {
        return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb));
 }
@@ -1256,16 +1275,17 @@ static struct dquot **ext4_get_dquots(struct inode *inode)
 }
 
 static const struct dquot_operations ext4_quota_operations = {
-       .get_reserved_space = ext4_get_reserved_space,
-       .write_dquot    = ext4_write_dquot,
-       .acquire_dquot  = ext4_acquire_dquot,
-       .release_dquot  = ext4_release_dquot,
-       .mark_dirty     = ext4_mark_dquot_dirty,
-       .write_info     = ext4_write_info,
-       .alloc_dquot    = dquot_alloc,
-       .destroy_dquot  = dquot_destroy,
-       .get_projid     = ext4_get_projid,
-       .get_next_id    = ext4_get_next_id,
+       .get_reserved_space     = ext4_get_reserved_space,
+       .write_dquot            = ext4_write_dquot,
+       .acquire_dquot          = ext4_acquire_dquot,
+       .release_dquot          = ext4_release_dquot,
+       .mark_dirty             = ext4_mark_dquot_dirty,
+       .write_info             = ext4_write_info,
+       .alloc_dquot            = dquot_alloc,
+       .destroy_dquot          = dquot_destroy,
+       .get_projid             = ext4_get_projid,
+       .get_inode_usage        = ext4_get_inode_usage,
+       .get_next_id            = ext4_get_next_id,
 };
 
 static const struct quotactl_ops ext4_qctl_operations = {
@@ -1328,7 +1348,7 @@ enum {
        Opt_inode_readahead_blks, Opt_journal_ioprio,
        Opt_dioread_nolock, Opt_dioread_lock,
        Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
-       Opt_max_dir_size_kb, Opt_nojournal_checksum,
+       Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
 };
 
 static const match_table_t tokens = {
@@ -1411,6 +1431,8 @@ static const match_table_t tokens = {
        {Opt_noinit_itable, "noinit_itable"},
        {Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
        {Opt_test_dummy_encryption, "test_dummy_encryption"},
+       {Opt_nombcache, "nombcache"},
+       {Opt_nombcache, "no_mbcache"},  /* for backward compatibility */
        {Opt_removed, "check=none"},    /* mount option from ext2/3 */
        {Opt_removed, "nocheck"},       /* mount option from ext2/3 */
        {Opt_removed, "reservation"},   /* mount option from ext2/3 */
@@ -1618,6 +1640,7 @@ static const struct mount_opts {
        {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT},
        {Opt_max_dir_size_kb, 0, MOPT_GTE0},
        {Opt_test_dummy_encryption, 0, MOPT_GTE0},
+       {Opt_nombcache, EXT4_MOUNT_NO_MBCACHE, MOPT_SET},
        {Opt_err, 0, 0}
 };
 
@@ -2077,7 +2100,7 @@ int ext4_seq_options_show(struct seq_file *seq, void *offset)
        struct super_block *sb = seq->private;
        int rc;
 
-       seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw");
+       seq_puts(seq, sb_rdonly(sb) ? "ro" : "rw");
        rc = _ext4_show_options(seq, sb, 1);
        seq_puts(seq, "\n");
        return rc;
@@ -2345,7 +2368,7 @@ static int ext4_check_descriptors(struct super_block *sb,
                                 "Checksum for group %u failed (%u!=%u)",
                                 i, le16_to_cpu(ext4_group_desc_csum(sb, i,
                                     gdp)), le16_to_cpu(gdp->bg_checksum));
-                       if (!(sb->s_flags & MS_RDONLY)) {
+                       if (!sb_rdonly(sb)) {
                                ext4_unlock_group(sb, i);
                                return 0;
                        }
@@ -3092,8 +3115,7 @@ int ext4_register_li_request(struct super_block *sb,
                goto out;
        }
 
-       if (first_not_zeroed == ngroups ||
-           (sb->s_flags & MS_RDONLY) ||
+       if (first_not_zeroed == ngroups || sb_rdonly(sb) ||
            !test_opt(sb, INIT_INODE_TABLE))
                goto out;
 
@@ -3445,7 +3467,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* Load the checksum driver */
-       if (ext4_has_feature_metadata_csum(sb)) {
+       if (ext4_has_feature_metadata_csum(sb) ||
+           ext4_has_feature_ea_inode(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.");
@@ -3467,7 +3490,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        /* Precompute checksum seed for all metadata */
        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))
+       else if (ext4_has_metadata_csum(sb) || ext4_has_feature_ea_inode(sb))
                sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid,
                                               sizeof(es->s_uuid));
 
@@ -3597,6 +3620,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                 "The Hurd can't support 64-bit file systems");
                        goto failed_mount;
                }
+
+               /*
+                * ea_inode feature uses l_i_version field which is not
+                * available in HURD_COMPAT mode.
+                */
+               if (ext4_has_feature_ea_inode(sb)) {
+                       ext4_msg(sb, KERN_ERR,
+                                "ea_inode feature is not supported for Hurd");
+                       goto failed_mount;
+               }
        }
 
        if (IS_EXT2_SB(sb)) {
@@ -3626,7 +3659,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
         * previously didn't change the revision level when setting the flags,
         * so there is a chance incompat flags are set on a rev 0 filesystem.
         */
-       if (!ext4_feature_set_ok(sb, (sb->s_flags & MS_RDONLY)))
+       if (!ext4_feature_set_ok(sb, (sb_rdonly(sb))))
                goto failed_mount;
 
        blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
@@ -3755,12 +3788,12 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        sbi->s_hash_unsigned = 3;
                else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) {
 #ifdef __CHAR_UNSIGNED__
-                       if (!(sb->s_flags & MS_RDONLY))
+                       if (!sb_rdonly(sb))
                                es->s_flags |=
                                        cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH);
                        sbi->s_hash_unsigned = 3;
 #else
-                       if (!(sb->s_flags & MS_RDONLY))
+                       if (!sb_rdonly(sb))
                                es->s_flags |=
                                        cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);
 #endif
@@ -3960,7 +3993,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        needs_recovery = (es->s_last_orphan != 0 ||
                          ext4_has_feature_journal_needs_recovery(sb));
 
-       if (ext4_has_feature_mmp(sb) && !(sb->s_flags & MS_RDONLY))
+       if (ext4_has_feature_mmp(sb) && !sb_rdonly(sb))
                if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
                        goto failed_mount3a;
 
@@ -3972,7 +4005,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                err = ext4_load_journal(sb, es, journal_devnum);
                if (err)
                        goto failed_mount3a;
-       } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) &&
+       } else if (test_opt(sb, NOLOAD) && !sb_rdonly(sb) &&
                   ext4_has_feature_journal_needs_recovery(sb)) {
                ext4_msg(sb, KERN_ERR, "required journal recovery "
                       "suppressed and not mounted read-only");
@@ -4061,10 +4094,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        sbi->s_journal->j_commit_callback = ext4_journal_commit_callback;
 
 no_journal:
-       sbi->s_mb_cache = ext4_xattr_create_cache();
-       if (!sbi->s_mb_cache) {
-               ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache");
-               goto failed_mount_wq;
+       if (!test_opt(sb, NO_MBCACHE)) {
+               sbi->s_ea_block_cache = ext4_xattr_create_cache();
+               if (!sbi->s_ea_block_cache) {
+                       ext4_msg(sb, KERN_ERR,
+                                "Failed to create ea_block_cache");
+                       goto failed_mount_wq;
+               }
+
+               if (ext4_has_feature_ea_inode(sb)) {
+                       sbi->s_ea_inode_cache = ext4_xattr_create_cache();
+                       if (!sbi->s_ea_inode_cache) {
+                               ext4_msg(sb, KERN_ERR,
+                                        "Failed to create ea_inode_cache");
+                               goto failed_mount_wq;
+                       }
+               }
        }
 
        if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) &&
@@ -4074,7 +4119,7 @@ no_journal:
                goto failed_mount_wq;
        }
 
-       if (DUMMY_ENCRYPTION_ENABLED(sbi) && !(sb->s_flags & MS_RDONLY) &&
+       if (DUMMY_ENCRYPTION_ENABLED(sbi) && !sb_rdonly(sb) &&
            !ext4_has_feature_encrypt(sb)) {
                ext4_set_feature_encrypt(sb);
                ext4_commit_super(sb, 1);
@@ -4128,7 +4173,7 @@ no_journal:
                goto failed_mount4;
        }
 
-       if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY))
+       if (ext4_setup_super(sb, es, sb_rdonly(sb)))
                sb->s_flags |= MS_RDONLY;
 
        /* determine the minimum size of new large inodes, if present */
@@ -4216,7 +4261,7 @@ no_journal:
 
 #ifdef CONFIG_QUOTA
        /* Enable quota usage during mount. */
-       if (ext4_has_feature_quota(sb) && !(sb->s_flags & MS_RDONLY)) {
+       if (ext4_has_feature_quota(sb) && !sb_rdonly(sb)) {
                err = ext4_enable_quotas(sb);
                if (err)
                        goto failed_mount8;
@@ -4296,9 +4341,13 @@ failed_mount4:
        if (EXT4_SB(sb)->rsv_conversion_wq)
                destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq);
 failed_mount_wq:
-       if (sbi->s_mb_cache) {
-               ext4_xattr_destroy_cache(sbi->s_mb_cache);
-               sbi->s_mb_cache = NULL;
+       if (sbi->s_ea_inode_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_inode_cache);
+               sbi->s_ea_inode_cache = NULL;
+       }
+       if (sbi->s_ea_block_cache) {
+               ext4_xattr_destroy_cache(sbi->s_ea_block_cache);
+               sbi->s_ea_block_cache = NULL;
        }
        if (sbi->s_journal) {
                jbd2_journal_destroy(sbi->s_journal);
@@ -4535,7 +4584,7 @@ static int ext4_load_journal(struct super_block *sb,
         * can get read-write access to the device.
         */
        if (ext4_has_feature_journal_needs_recovery(sb)) {
-               if (sb->s_flags & MS_RDONLY) {
+               if (sb_rdonly(sb)) {
                        ext4_msg(sb, KERN_INFO, "INFO: recovery "
                                        "required on readonly filesystem");
                        if (really_read_only) {
@@ -4690,8 +4739,7 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
        if (jbd2_journal_flush(journal) < 0)
                goto out;
 
-       if (ext4_has_feature_journal_needs_recovery(sb) &&
-           sb->s_flags & MS_RDONLY) {
+       if (ext4_has_feature_journal_needs_recovery(sb) && sb_rdonly(sb)) {
                ext4_clear_feature_journal_needs_recovery(sb);
                ext4_commit_super(sb, 1);
        }
@@ -4747,7 +4795,7 @@ int ext4_force_commit(struct super_block *sb)
 {
        journal_t *journal;
 
-       if (sb->s_flags & MS_RDONLY)
+       if (sb_rdonly(sb))
                return 0;
 
        journal = EXT4_SB(sb)->s_journal;
@@ -4812,7 +4860,7 @@ static int ext4_freeze(struct super_block *sb)
        int error = 0;
        journal_t *journal;
 
-       if (sb->s_flags & MS_RDONLY)
+       if (sb_rdonly(sb))
                return 0;
 
        journal = EXT4_SB(sb)->s_journal;
@@ -4847,7 +4895,7 @@ out:
  */
 static int ext4_unfreeze(struct super_block *sb)
 {
-       if ((sb->s_flags & MS_RDONLY) || ext4_forced_shutdown(EXT4_SB(sb)))
+       if (sb_rdonly(sb) || ext4_forced_shutdown(EXT4_SB(sb)))
                return 0;
 
        if (EXT4_SB(sb)->s_journal) {
@@ -4957,6 +5005,12 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
                }
        }
 
+       if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_NO_MBCACHE) {
+               ext4_msg(sb, KERN_ERR, "can't enable nombcache during remount");
+               err = -EINVAL;
+               goto restore_opts;
+       }
+
        if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX) {
                ext4_msg(sb, KERN_WARNING, "warning: refusing change of "
                        "dax flag with busy inodes while remounting");
@@ -4979,7 +5033,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
        if (*flags & MS_LAZYTIME)
                sb->s_flags |= MS_LAZYTIME;
 
-       if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {
+       if ((bool)(*flags & MS_RDONLY) != sb_rdonly(sb)) {
                if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {
                        err = -EROFS;
                        goto restore_opts;
@@ -5074,7 +5128,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
         * Reinitialize lazy itable initialization thread based on
         * current settings
         */
-       if ((sb->s_flags & MS_RDONLY) || !test_opt(sb, INIT_INODE_TABLE))
+       if (sb_rdonly(sb) || !test_opt(sb, INIT_INODE_TABLE))
                ext4_unregister_li_request(sb);
        else {
                ext4_group_t first_not_zeroed;
@@ -5646,7 +5700,7 @@ static inline int ext2_feature_set_ok(struct super_block *sb)
 {
        if (ext4_has_unknown_ext2_incompat_features(sb))
                return 0;
-       if (sb->s_flags & MS_RDONLY)
+       if (sb_rdonly(sb))
                return 1;
        if (ext4_has_unknown_ext2_ro_compat_features(sb))
                return 0;
@@ -5677,7 +5731,7 @@ static inline int ext3_feature_set_ok(struct super_block *sb)
                return 0;
        if (!ext4_has_feature_journal(sb))
                return 0;
-       if (sb->s_flags & MS_RDONLY)
+       if (sb_rdonly(sb))
                return 1;
        if (ext4_has_unknown_ext3_ro_compat_features(sb))
                return 0;