Merge tag 'vfs-6.7.fsid' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[linux-2.6-block.git] / fs / f2fs / super.c
index 60cfa11f65bf38e8e34ac48e583fbefc22460071..033af907c3b1dc3059874fc689a32c0f0aaa45b2 100644 (file)
@@ -83,11 +83,26 @@ void f2fs_build_fault_attr(struct f2fs_sb_info *sbi, unsigned int rate,
 #endif
 
 /* f2fs-wide shrinker description */
-static struct shrinker f2fs_shrinker_info = {
-       .scan_objects = f2fs_shrink_scan,
-       .count_objects = f2fs_shrink_count,
-       .seeks = DEFAULT_SEEKS,
-};
+static struct shrinker *f2fs_shrinker_info;
+
+static int __init f2fs_init_shrinker(void)
+{
+       f2fs_shrinker_info = shrinker_alloc(0, "f2fs-shrinker");
+       if (!f2fs_shrinker_info)
+               return -ENOMEM;
+
+       f2fs_shrinker_info->count_objects = f2fs_shrink_count;
+       f2fs_shrinker_info->scan_objects = f2fs_shrink_scan;
+
+       shrinker_register(f2fs_shrinker_info);
+
+       return 0;
+}
+
+static void f2fs_exit_shrinker(void)
+{
+       shrinker_free(f2fs_shrinker_info);
+}
 
 enum {
        Opt_gc_background,
@@ -547,6 +562,29 @@ static int f2fs_set_test_dummy_encryption(struct super_block *sb,
 }
 
 #ifdef CONFIG_F2FS_FS_COMPRESSION
+static bool is_compress_extension_exist(struct f2fs_sb_info *sbi,
+                                       const char *new_ext, bool is_ext)
+{
+       unsigned char (*ext)[F2FS_EXTENSION_LEN];
+       int ext_cnt;
+       int i;
+
+       if (is_ext) {
+               ext = F2FS_OPTION(sbi).extensions;
+               ext_cnt = F2FS_OPTION(sbi).compress_ext_cnt;
+       } else {
+               ext = F2FS_OPTION(sbi).noextensions;
+               ext_cnt = F2FS_OPTION(sbi).nocompress_ext_cnt;
+       }
+
+       for (i = 0; i < ext_cnt; i++) {
+               if (!strcasecmp(new_ext, ext[i]))
+                       return true;
+       }
+
+       return false;
+}
+
 /*
  * 1. The same extension name cannot not appear in both compress and non-compress extension
  * at the same time.
@@ -1149,6 +1187,11 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                                return -EINVAL;
                        }
 
+                       if (is_compress_extension_exist(sbi, name, true)) {
+                               kfree(name);
+                               break;
+                       }
+
                        strcpy(ext[ext_cnt], name);
                        F2FS_OPTION(sbi).compress_ext_cnt++;
                        kfree(name);
@@ -1173,6 +1216,11 @@ static int parse_options(struct super_block *sb, char *options, bool is_remount)
                                return -EINVAL;
                        }
 
+                       if (is_compress_extension_exist(sbi, name, false)) {
+                               kfree(name);
+                               break;
+                       }
+
                        strcpy(noext[noext_cnt], name);
                        F2FS_OPTION(sbi).nocompress_ext_cnt++;
                        kfree(name);
@@ -1562,7 +1610,7 @@ static void destroy_device_list(struct f2fs_sb_info *sbi)
 
        for (i = 0; i < sbi->s_ndevs; i++) {
                if (i > 0)
-                       blkdev_put(FDEV(i).bdev, sbi->sb);
+                       bdev_release(FDEV(i).bdev_handle);
 #ifdef CONFIG_BLK_DEV_ZONED
                kvfree(FDEV(i).blkz_seq);
 #endif
@@ -1629,7 +1677,7 @@ static void f2fs_put_super(struct super_block *sb)
 
        f2fs_wait_on_all_pages(sbi, F2FS_WB_CP_DATA);
 
-       if (err) {
+       if (err || f2fs_cp_error(sbi)) {
                truncate_inode_pages_final(NODE_MAPPING(sbi));
                truncate_inode_pages_final(META_MAPPING(sbi));
        }
@@ -2286,9 +2334,9 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        unsigned long old_sb_flags;
        int err;
        bool need_restart_gc = false, need_stop_gc = false;
-       bool need_restart_ckpt = false, need_stop_ckpt = false;
        bool need_restart_flush = false, need_stop_flush = false;
        bool need_restart_discard = false, need_stop_discard = false;
+       bool need_enable_checkpoint = false, need_disable_checkpoint = false;
        bool no_read_extent_cache = !test_opt(sbi, READ_EXTENT_CACHE);
        bool no_age_extent_cache = !test_opt(sbi, AGE_EXTENT_CACHE);
        bool enable_checkpoint = !test_opt(sbi, DISABLE_CHECKPOINT);
@@ -2452,24 +2500,6 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
                clear_sbi_flag(sbi, SBI_IS_CLOSE);
        }
 
-       if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) ||
-                       !test_opt(sbi, MERGE_CHECKPOINT)) {
-               f2fs_stop_ckpt_thread(sbi);
-               need_restart_ckpt = true;
-       } else {
-               /* Flush if the prevous checkpoint, if exists. */
-               f2fs_flush_ckpt_thread(sbi);
-
-               err = f2fs_start_ckpt_thread(sbi);
-               if (err) {
-                       f2fs_err(sbi,
-                           "Failed to start F2FS issue_checkpoint_thread (%d)",
-                           err);
-                       goto restore_gc;
-               }
-               need_stop_ckpt = true;
-       }
-
        /*
         * We stop issue flush thread if FS is mounted as RO
         * or if flush_merge is not passed in mount option.
@@ -2481,7 +2511,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
        } else {
                err = f2fs_create_flush_cmd_control(sbi);
                if (err)
-                       goto restore_ckpt;
+                       goto restore_gc;
                need_stop_flush = true;
        }
 
@@ -2503,8 +2533,31 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
                        err = f2fs_disable_checkpoint(sbi);
                        if (err)
                                goto restore_discard;
+                       need_enable_checkpoint = true;
                } else {
                        f2fs_enable_checkpoint(sbi);
+                       need_disable_checkpoint = true;
+               }
+       }
+
+       /*
+        * Place this routine at the end, since a new checkpoint would be
+        * triggered while remount and we need to take care of it before
+        * returning from remount.
+        */
+       if ((*flags & SB_RDONLY) || test_opt(sbi, DISABLE_CHECKPOINT) ||
+                       !test_opt(sbi, MERGE_CHECKPOINT)) {
+               f2fs_stop_ckpt_thread(sbi);
+       } else {
+               /* Flush if the prevous checkpoint, if exists. */
+               f2fs_flush_ckpt_thread(sbi);
+
+               err = f2fs_start_ckpt_thread(sbi);
+               if (err) {
+                       f2fs_err(sbi,
+                           "Failed to start F2FS issue_checkpoint_thread (%d)",
+                           err);
+                       goto restore_checkpoint;
                }
        }
 
@@ -2522,6 +2575,13 @@ skip:
        adjust_unusable_cap_perc(sbi);
        *flags = (*flags & ~SB_LAZYTIME) | (sb->s_flags & SB_LAZYTIME);
        return 0;
+restore_checkpoint:
+       if (need_enable_checkpoint) {
+               f2fs_enable_checkpoint(sbi);
+       } else if (need_disable_checkpoint) {
+               if (f2fs_disable_checkpoint(sbi))
+                       f2fs_warn(sbi, "checkpoint has not been disabled");
+       }
 restore_discard:
        if (need_restart_discard) {
                if (f2fs_start_discard_thread(sbi))
@@ -2537,13 +2597,6 @@ restore_flush:
                clear_opt(sbi, FLUSH_MERGE);
                f2fs_destroy_flush_cmd_control(sbi, false);
        }
-restore_ckpt:
-       if (need_restart_ckpt) {
-               if (f2fs_start_ckpt_thread(sbi))
-                       f2fs_warn(sbi, "background ckpt thread has stopped");
-       } else if (need_stop_ckpt) {
-               f2fs_stop_ckpt_thread(sbi);
-       }
 restore_gc:
        if (need_restart_gc) {
                if (f2fs_start_gc_thread(sbi))
@@ -2710,7 +2763,7 @@ retry:
 
        if (len == towrite)
                return err;
-       inode->i_mtime = inode_set_ctime_current(inode);
+       inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        f2fs_mark_inode_dirty_sync(inode, false);
        return len - towrite;
 }
@@ -3203,13 +3256,6 @@ static bool f2fs_has_stable_inodes(struct super_block *sb)
        return true;
 }
 
-static void f2fs_get_ino_and_lblk_bits(struct super_block *sb,
-                                      int *ino_bits_ret, int *lblk_bits_ret)
-{
-       *ino_bits_ret = 8 * sizeof(nid_t);
-       *lblk_bits_ret = 8 * sizeof(block_t);
-}
-
 static struct block_device **f2fs_get_devices(struct super_block *sb,
                                              unsigned int *num_devs)
 {
@@ -3231,13 +3277,15 @@ static struct block_device **f2fs_get_devices(struct super_block *sb,
 }
 
 static const struct fscrypt_operations f2fs_cryptops = {
-       .key_prefix             = "f2fs:",
+       .needs_bounce_pages     = 1,
+       .has_32bit_inodes       = 1,
+       .supports_subblock_data_units = 1,
+       .legacy_key_prefix      = "f2fs:",
        .get_context            = f2fs_get_context,
        .set_context            = f2fs_set_context,
        .get_dummy_policy       = f2fs_get_dummy_policy,
        .empty_dir              = f2fs_empty_dir,
        .has_stable_inodes      = f2fs_has_stable_inodes,
-       .get_ino_and_lblk_bits  = f2fs_get_ino_and_lblk_bits,
        .get_devices            = f2fs_get_devices,
 };
 #endif
@@ -3470,7 +3518,7 @@ static int sanity_check_raw_super(struct f2fs_sb_info *sbi,
                return -EFSCORRUPTED;
        }
 
-       /* Currently, support 512/1024/2048/4096 bytes sector size */
+       /* Currently, support 512/1024/2048/4096/16K bytes sector size */
        if (le32_to_cpu(raw_super->log_sectorsize) >
                                F2FS_MAX_LOG_SECTOR_SIZE ||
                le32_to_cpu(raw_super->log_sectorsize) <
@@ -4199,7 +4247,7 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 
        for (i = 0; i < max_devices; i++) {
                if (i == 0)
-                       FDEV(0).bdev = sbi->sb->s_bdev;
+                       FDEV(0).bdev_handle = sbi->sb->s_bdev_handle;
                else if (!RDEV(i).path[0])
                        break;
 
@@ -4219,13 +4267,14 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
                                FDEV(i).end_blk = FDEV(i).start_blk +
                                        (FDEV(i).total_segments <<
                                        sbi->log_blocks_per_seg) - 1;
-                               FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path,
-                                       mode, sbi->sb, NULL);
+                               FDEV(i).bdev_handle = bdev_open_by_path(
+                                       FDEV(i).path, mode, sbi->sb, NULL);
                        }
                }
-               if (IS_ERR(FDEV(i).bdev))
-                       return PTR_ERR(FDEV(i).bdev);
+               if (IS_ERR(FDEV(i).bdev_handle))
+                       return PTR_ERR(FDEV(i).bdev_handle);
 
+               FDEV(i).bdev = FDEV(i).bdev_handle->bdev;
                /* to release errored devices */
                sbi->s_ndevs = i + 1;
 
@@ -4916,7 +4965,7 @@ static int __init init_f2fs_fs(void)
        int err;
 
        if (PAGE_SIZE != F2FS_BLKSIZE) {
-               printk("F2FS not supported on PAGE_SIZE(%lu) != %d\n",
+               printk("F2FS not supported on PAGE_SIZE(%lu) != BLOCK_SIZE(%lu)\n",
                                PAGE_SIZE, F2FS_BLKSIZE);
                return -EINVAL;
        }
@@ -4945,7 +4994,7 @@ static int __init init_f2fs_fs(void)
        err = f2fs_init_sysfs();
        if (err)
                goto free_garbage_collection_cache;
-       err = register_shrinker(&f2fs_shrinker_info, "f2fs-shrinker");
+       err = f2fs_init_shrinker();
        if (err)
                goto free_sysfs;
        err = register_filesystem(&f2fs_fs_type);
@@ -4990,7 +5039,7 @@ free_root_stats:
        f2fs_destroy_root_stats();
        unregister_filesystem(&f2fs_fs_type);
 free_shrinker:
-       unregister_shrinker(&f2fs_shrinker_info);
+       f2fs_exit_shrinker();
 free_sysfs:
        f2fs_exit_sysfs();
 free_garbage_collection_cache:
@@ -5022,7 +5071,7 @@ static void __exit exit_f2fs_fs(void)
        f2fs_destroy_post_read_processing();
        f2fs_destroy_root_stats();
        unregister_filesystem(&f2fs_fs_type);
-       unregister_shrinker(&f2fs_shrinker_info);
+       f2fs_exit_shrinker();
        f2fs_exit_sysfs();
        f2fs_destroy_garbage_collection_cache();
        f2fs_destroy_extent_cache();