Merge tag 'for-5.14-rc6-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave...
[linux-2.6-microblaze.git] / fs / f2fs / super.c
index 7d325bf..8fecd30 100644 (file)
@@ -148,8 +148,10 @@ enum {
        Opt_compress_algorithm,
        Opt_compress_log_size,
        Opt_compress_extension,
+       Opt_nocompress_extension,
        Opt_compress_chksum,
        Opt_compress_mode,
+       Opt_compress_cache,
        Opt_atgc,
        Opt_gc_merge,
        Opt_nogc_merge,
@@ -222,8 +224,10 @@ static match_table_t f2fs_tokens = {
        {Opt_compress_algorithm, "compress_algorithm=%s"},
        {Opt_compress_log_size, "compress_log_size=%u"},
        {Opt_compress_extension, "compress_extension=%s"},
+       {Opt_nocompress_extension, "nocompress_extension=%s"},
        {Opt_compress_chksum, "compress_chksum"},
        {Opt_compress_mode, "compress_mode=%s"},
+       {Opt_compress_cache, "compress_cache"},
        {Opt_atgc, "atgc"},
        {Opt_gc_merge, "gc_merge"},
        {Opt_nogc_merge, "nogc_merge"},
@@ -275,6 +279,24 @@ static int f2fs_sb_read_encoding(const struct f2fs_super_block *sb,
 
        return 0;
 }
+
+struct kmem_cache *f2fs_cf_name_slab;
+static int __init f2fs_create_casefold_cache(void)
+{
+       f2fs_cf_name_slab = f2fs_kmem_cache_create("f2fs_casefolded_name",
+                                                       F2FS_NAME_LEN);
+       if (!f2fs_cf_name_slab)
+               return -ENOMEM;
+       return 0;
+}
+
+static void f2fs_destroy_casefold_cache(void)
+{
+       kmem_cache_destroy(f2fs_cf_name_slab);
+}
+#else
+static int __init f2fs_create_casefold_cache(void) { return 0; }
+static void f2fs_destroy_casefold_cache(void) { }
 #endif
 
 static inline void limit_reserve_root(struct f2fs_sb_info *sbi)
@@ -473,6 +495,43 @@ static int f2fs_set_test_dummy_encryption(struct super_block *sb,
 }
 
 #ifdef CONFIG_F2FS_FS_COMPRESSION
+/*
+ * 1. The same extension name cannot not appear in both compress and non-compress extension
+ * at the same time.
+ * 2. If the compress extension specifies all files, the types specified by the non-compress
+ * extension will be treated as special cases and will not be compressed.
+ * 3. Don't allow the non-compress extension specifies all files.
+ */
+static int f2fs_test_compress_extension(struct f2fs_sb_info *sbi)
+{
+       unsigned char (*ext)[F2FS_EXTENSION_LEN];
+       unsigned char (*noext)[F2FS_EXTENSION_LEN];
+       int ext_cnt, noext_cnt, index = 0, no_index = 0;
+
+       ext = F2FS_OPTION(sbi).extensions;
+       ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
+       noext = F2FS_OPTION(sbi).noextensions;
+       noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
+
+       if (!noext_cnt)
+               return 0;
+
+       for (no_index = 0; no_index < noext_cnt; no_index++) {
+               if (!strcasecmp("*", noext[no_index])) {
+                       f2fs_info(sbi, "Don't allow the nocompress extension specifies all files");
+                       return -EINVAL;
+               }
+               for (index = 0; index < ext_cnt; index++) {
+                       if (!strcasecmp(ext[index], noext[no_index])) {
+                               f2fs_info(sbi, "Don't allow the same extension %s appear in both compress and nocompress extension",
+                                               ext[index]);
+                               return -EINVAL;
+                       }
+               }
+       }
+       return 0;
+}
+
 #ifdef CONFIG_F2FS_FS_LZ4
 static int f2fs_set_lz4hc_level(struct f2fs_sb_info *sbi, const char *str)
 {
@@ -546,7 +605,8 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
        substring_t args[MAX_OPT_ARGS];
 #ifdef CONFIG_F2FS_FS_COMPRESSION
        unsigned char (*ext)[F2FS_EXTENSION_LEN];
-       int ext_cnt;
+       unsigned char (*noext)[F2FS_EXTENSION_LEN];
+       int ext_cnt, noext_cnt;
 #endif
        char *p, *name;
        int arg = 0;
@@ -555,7 +615,7 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
        int ret;
 
        if (!options)
-               return 0;
+               goto default_check;
 
        while ((p = strsep(&options, ",")) != NULL) {
                int token;
@@ -1049,6 +1109,30 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                        F2FS_OPTION(sbi).compress_ext_cnt++;
                        kfree(name);
                        break;
+               case Opt_nocompress_extension:
+                       if (!f2fs_sb_has_compression(sbi)) {
+                               f2fs_info(sbi, "Image doesn't support compression");
+                               break;
+                       }
+                       name = match_strdup(&args[0]);
+                       if (!name)
+                               return -ENOMEM;
+
+                       noext = F2FS_OPTION(sbi).noextensions;
+                       noext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
+
+                       if (strlen(name) >= F2FS_EXTENSION_LEN ||
+                               noext_cnt >= COMPRESS_EXT_NUM) {
+                               f2fs_err(sbi,
+                                       "invalid extension length/number");
+                               kfree(name);
+                               return -EINVAL;
+                       }
+
+                       strcpy(noext[noext_cnt], name);
+                       F2FS_OPTION(sbi).nocompress_ext_cnt++;
+                       kfree(name);
+                       break;
                case Opt_compress_chksum:
                        F2FS_OPTION(sbi).compress_chksum = true;
                        break;
@@ -1066,12 +1150,17 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                        }
                        kfree(name);
                        break;
+               case Opt_compress_cache:
+                       set_opt(sbi, COMPRESS_CACHE);
+                       break;
 #else
                case Opt_compress_algorithm:
                case Opt_compress_log_size:
                case Opt_compress_extension:
+               case Opt_nocompress_extension:
                case Opt_compress_chksum:
                case Opt_compress_mode:
+               case Opt_compress_cache:
                        f2fs_info(sbi, "compression options not supported");
                        break;
 #endif
@@ -1090,6 +1179,7 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                        return -EINVAL;
                }
        }
+default_check:
 #ifdef CONFIG_QUOTA
        if (f2fs_check_quota_options(sbi))
                return -EINVAL;
@@ -1122,6 +1212,13 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
        }
 #endif
 
+#ifdef CONFIG_F2FS_FS_COMPRESSION
+       if (f2fs_test_compress_extension(sbi)) {
+               f2fs_err(sbi, "invalid compress or nocompress extension");
+               return -EINVAL;
+       }
+#endif
+
        if (F2FS_IO_SIZE_BITS(sbi) && !f2fs_lfs_mode(sbi)) {
                f2fs_err(sbi, "Should set mode=lfs with %uKB-sized IO",
                         F2FS_IO_SIZE_KB(sbi));
@@ -1153,7 +1250,7 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
        }
 
        if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) {
-               f2fs_err(sbi, "LFS not compatible with checkpoint=disable\n");
+               f2fs_err(sbi, "LFS not compatible with checkpoint=disable");
                return -EINVAL;
        }
 
@@ -1162,6 +1259,11 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
         */
        if (F2FS_OPTION(sbi).active_logs != NR_CURSEG_TYPE)
                F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
+
+       if (f2fs_sb_has_readonly(sbi) && !f2fs_readonly(sbi->sb)) {
+               f2fs_err(sbi, "Allow to mount readonly mode only");
+               return -EROFS;
+       }
        return 0;
 }
 
@@ -1403,6 +1505,8 @@ static void f2fs_put_super(struct super_block *sb)
 
        f2fs_bug_on(sbi, sbi->fsync_node_num);
 
+       f2fs_destroy_compress_inode(sbi);
+
        iput(sbi->node_inode);
        sbi->node_inode = NULL;
 
@@ -1665,6 +1769,11 @@ static inline void f2fs_show_compress_options(struct seq_file *seq,
                        F2FS_OPTION(sbi).extensions[i]);
        }
 
+       for (i = 0; i < F2FS_OPTION(sbi).nocompress_ext_cnt; i++) {
+               seq_printf(seq, ",nocompress_extension=%s",
+                       F2FS_OPTION(sbi).noextensions[i]);
+       }
+
        if (F2FS_OPTION(sbi).compress_chksum)
                seq_puts(seq, ",compress_chksum");
 
@@ -1672,6 +1781,9 @@ static inline void f2fs_show_compress_options(struct seq_file *seq,
                seq_printf(seq, ",compress_mode=%s", "fs");
        else if (F2FS_OPTION(sbi).compress_mode == COMPR_MODE_USER)
                seq_printf(seq, ",compress_mode=%s", "user");
+
+       if (test_opt(sbi, COMPRESS_CACHE))
+               seq_puts(seq, ",compress_cache");
 }
 #endif
 
@@ -1819,7 +1931,11 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 static void default_options(struct f2fs_sb_info *sbi)
 {
        /* init some FS parameters */
-       F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE;
+       if (f2fs_sb_has_readonly(sbi))
+               F2FS_OPTION(sbi).active_logs = NR_CURSEG_RO_TYPE;
+       else
+               F2FS_OPTION(sbi).active_logs = NR_CURSEG_PERSIST_TYPE;
+
        F2FS_OPTION(sbi).inline_xattr_size = DEFAULT_INLINE_XATTR_ADDRS;
        F2FS_OPTION(sbi).whint_mode = WHINT_MODE_OFF;
        F2FS_OPTION(sbi).alloc_mode = ALLOC_MODE_DEFAULT;
@@ -1949,6 +2065,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        bool disable_checkpoint = test_opt(sbi, DISABLE_CHECKPOINT);
        bool no_io_align = !F2FS_IO_ALIGNED(sbi);
        bool no_atgc = !test_opt(sbi, ATGC);
+       bool no_compress_cache = !test_opt(sbi, COMPRESS_CACHE);
        bool checkpoint_changed;
 #ifdef CONFIG_QUOTA
        int i, j;
@@ -2004,6 +2121,11 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        if (f2fs_readonly(sb) && (*flags & SB_RDONLY))
                goto skip;
 
+       if (f2fs_sb_has_readonly(sbi) && !(*flags & SB_RDONLY)) {
+               err = -EROFS;
+               goto restore_opts;
+       }
+
 #ifdef CONFIG_QUOTA
        if (!f2fs_readonly(sb) && (*flags & SB_RDONLY)) {
                err = dquot_suspend(sb, -1);
@@ -2041,6 +2163,12 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
                goto restore_opts;
        }
 
+       if (no_compress_cache == !!test_opt(sbi, COMPRESS_CACHE)) {
+               err = -EINVAL;
+               f2fs_warn(sbi, "switch compress_cache option is not allowed");
+               goto restore_opts;
+       }
+
        if ((*flags & SB_RDONLY) && test_opt(sbi, DISABLE_CHECKPOINT)) {
                err = -EINVAL;
                f2fs_warn(sbi, "disabling checkpoint not compatible with read-only");
@@ -3137,14 +3265,15 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
        ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
        reserved_segments = le32_to_cpu(ckpt->rsvd_segment_count);
 
-       if (unlikely(fsmeta < F2FS_MIN_META_SEGMENTS ||
+       if (!f2fs_sb_has_readonly(sbi) &&
+                       unlikely(fsmeta < F2FS_MIN_META_SEGMENTS ||
                        ovp_segments == 0 || reserved_segments == 0)) {
                f2fs_err(sbi, "Wrong layout: check mkfs.f2fs version");
                return 1;
        }
-
        user_block_count = le64_to_cpu(ckpt->user_block_count);
-       segment_count_main = le32_to_cpu(raw_super->segment_count_main);
+       segment_count_main = le32_to_cpu(raw_super->segment_count_main) +
+                       (f2fs_sb_has_readonly(sbi) ? 1 : 0);
        log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
        if (!user_block_count || user_block_count >=
                        segment_count_main << log_blocks_per_seg) {
@@ -3175,6 +3304,10 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                if (le32_to_cpu(ckpt->cur_node_segno[i]) >= main_segs ||
                        le16_to_cpu(ckpt->cur_node_blkoff[i]) >= blocks_per_seg)
                        return 1;
+
+               if (f2fs_sb_has_readonly(sbi))
+                       goto check_data;
+
                for (j = i + 1; j < NR_CURSEG_NODE_TYPE; j++) {
                        if (le32_to_cpu(ckpt->cur_node_segno[i]) ==
                                le32_to_cpu(ckpt->cur_node_segno[j])) {
@@ -3185,10 +3318,15 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                        }
                }
        }
+check_data:
        for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) {
                if (le32_to_cpu(ckpt->cur_data_segno[i]) >= main_segs ||
                        le16_to_cpu(ckpt->cur_data_blkoff[i]) >= blocks_per_seg)
                        return 1;
+
+               if (f2fs_sb_has_readonly(sbi))
+                       goto skip_cross;
+
                for (j = i + 1; j < NR_CURSEG_DATA_TYPE; j++) {
                        if (le32_to_cpu(ckpt->cur_data_segno[i]) ==
                                le32_to_cpu(ckpt->cur_data_segno[j])) {
@@ -3210,7 +3348,7 @@ int f2fs_sanity_check_ckpt(struct f2fs_sb_info *sbi)
                        }
                }
        }
-
+skip_cross:
        sit_bitmap_size = le32_to_cpu(ckpt->sit_ver_bitmap_bytesize);
        nat_bitmap_size = le32_to_cpu(ckpt->nat_ver_bitmap_bytesize);
 
@@ -3555,7 +3693,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 #ifdef CONFIG_BLK_DEV_ZONED
                if (bdev_zoned_model(FDEV(i).bdev) == BLK_ZONED_HM &&
                                !f2fs_sb_has_blkzoned(sbi)) {
-                       f2fs_err(sbi, "Zoned block device feature not enabled\n");
+                       f2fs_err(sbi, "Zoned block device feature not enabled");
                        return -EINVAL;
                }
                if (bdev_zoned_model(FDEV(i).bdev) != BLK_ZONED_NONE) {
@@ -3940,10 +4078,14 @@ try_onemore:
                goto free_node_inode;
        }
 
-       err = f2fs_register_sysfs(sbi);
+       err = f2fs_init_compress_inode(sbi);
        if (err)
                goto free_root_inode;
 
+       err = f2fs_register_sysfs(sbi);
+       if (err)
+               goto free_compress_inode;
+
 #ifdef CONFIG_QUOTA
        /* Enable quota usage during mount */
        if (f2fs_sb_has_quota_ino(sbi) && !f2fs_readonly(sb)) {
@@ -4084,6 +4226,8 @@ free_meta:
        /* evict some inodes being cached by GC */
        evict_inodes(sb);
        f2fs_unregister_sysfs(sbi);
+free_compress_inode:
+       f2fs_destroy_compress_inode(sbi);
 free_root_inode:
        dput(sb->s_root);
        sb->s_root = NULL;
@@ -4162,6 +4306,15 @@ static void kill_f2fs_super(struct super_block *sb)
                f2fs_stop_gc_thread(sbi);
                f2fs_stop_discard_thread(sbi);
 
+#ifdef CONFIG_F2FS_FS_COMPRESSION
+               /*
+                * latter evict_inode() can bypass checking and invalidating
+                * compress inode cache.
+                */
+               if (test_opt(sbi, COMPRESS_CACHE))
+                       truncate_inode_pages_final(COMPRESS_MAPPING(sbi));
+#endif
+
                if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) ||
                                !is_set_ckpt_flags(sbi, CP_UMOUNT_FLAG)) {
                        struct cp_control cpc = {
@@ -4227,9 +4380,12 @@ static int __init init_f2fs_fs(void)
        err = f2fs_create_checkpoint_caches();
        if (err)
                goto free_segment_manager_caches;
-       err = f2fs_create_extent_cache();
+       err = f2fs_create_recovery_cache();
        if (err)
                goto free_checkpoint_caches;
+       err = f2fs_create_extent_cache();
+       if (err)
+               goto free_recovery_cache;
        err = f2fs_create_garbage_collection_cache();
        if (err)
                goto free_extent_cache;
@@ -4258,7 +4414,12 @@ static int __init init_f2fs_fs(void)
        err = f2fs_init_compress_cache();
        if (err)
                goto free_compress_mempool;
+       err = f2fs_create_casefold_cache();
+       if (err)
+               goto free_compress_cache;
        return 0;
+free_compress_cache:
+       f2fs_destroy_compress_cache();
 free_compress_mempool:
        f2fs_destroy_compress_mempool();
 free_bioset:
@@ -4278,6 +4439,8 @@ free_garbage_collection_cache:
        f2fs_destroy_garbage_collection_cache();
 free_extent_cache:
        f2fs_destroy_extent_cache();
+free_recovery_cache:
+       f2fs_destroy_recovery_cache();
 free_checkpoint_caches:
        f2fs_destroy_checkpoint_caches();
 free_segment_manager_caches:
@@ -4292,6 +4455,7 @@ fail:
 
 static void __exit exit_f2fs_fs(void)
 {
+       f2fs_destroy_casefold_cache();
        f2fs_destroy_compress_cache();
        f2fs_destroy_compress_mempool();
        f2fs_destroy_bioset();
@@ -4303,6 +4467,7 @@ static void __exit exit_f2fs_fs(void)
        f2fs_exit_sysfs();
        f2fs_destroy_garbage_collection_cache();
        f2fs_destroy_extent_cache();
+       f2fs_destroy_recovery_cache();
        f2fs_destroy_checkpoint_caches();
        f2fs_destroy_segment_manager_caches();
        f2fs_destroy_node_manager_caches();
@@ -4315,4 +4480,5 @@ module_exit(exit_f2fs_fs)
 MODULE_AUTHOR("Samsung Electronics's Praesto Team");
 MODULE_DESCRIPTION("Flash Friendly File System");
 MODULE_LICENSE("GPL");
+MODULE_SOFTDEP("pre: crc32");