Merge tag 'for-f2fs-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[platform/kernel/linux-starfive.git] / fs / f2fs / super.c
index a831303..96fe8ed 100644 (file)
@@ -89,6 +89,7 @@ enum {
        Opt_active_logs,
        Opt_disable_ext_identify,
        Opt_inline_xattr,
+       Opt_noinline_xattr,
        Opt_inline_data,
        Opt_inline_dentry,
        Opt_noinline_dentry,
@@ -101,6 +102,7 @@ enum {
        Opt_noinline_data,
        Opt_data_flush,
        Opt_mode,
+       Opt_io_size_bits,
        Opt_fault_injection,
        Opt_lazytime,
        Opt_nolazytime,
@@ -121,6 +123,7 @@ static match_table_t f2fs_tokens = {
        {Opt_active_logs, "active_logs=%u"},
        {Opt_disable_ext_identify, "disable_ext_identify"},
        {Opt_inline_xattr, "inline_xattr"},
+       {Opt_noinline_xattr, "noinline_xattr"},
        {Opt_inline_data, "inline_data"},
        {Opt_inline_dentry, "inline_dentry"},
        {Opt_noinline_dentry, "noinline_dentry"},
@@ -133,6 +136,7 @@ static match_table_t f2fs_tokens = {
        {Opt_noinline_data, "noinline_data"},
        {Opt_data_flush, "data_flush"},
        {Opt_mode, "mode=%s"},
+       {Opt_io_size_bits, "io_bits=%u"},
        {Opt_fault_injection, "fault_injection=%u"},
        {Opt_lazytime, "lazytime"},
        {Opt_nolazytime, "nolazytime"},
@@ -143,6 +147,7 @@ static match_table_t f2fs_tokens = {
 enum {
        GC_THREAD,      /* struct f2fs_gc_thread */
        SM_INFO,        /* struct f2fs_sm_info */
+       DCC_INFO,       /* struct discard_cmd_control */
        NM_INFO,        /* struct f2fs_nm_info */
        F2FS_SBI,       /* struct f2fs_sb_info */
 #ifdef CONFIG_F2FS_FAULT_INJECTION
@@ -166,6 +171,8 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
                return (unsigned char *)sbi->gc_thread;
        else if (struct_type == SM_INFO)
                return (unsigned char *)SM_I(sbi);
+       else if (struct_type == DCC_INFO)
+               return (unsigned char *)SM_I(sbi)->dcc_info;
        else if (struct_type == NM_INFO)
                return (unsigned char *)NM_I(sbi);
        else if (struct_type == F2FS_SBI)
@@ -281,7 +288,7 @@ F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
 F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
-F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards);
+F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
@@ -439,6 +446,9 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_inline_xattr:
                        set_opt(sbi, INLINE_XATTR);
                        break;
+               case Opt_noinline_xattr:
+                       clear_opt(sbi, INLINE_XATTR);
+                       break;
 #else
                case Opt_user_xattr:
                        f2fs_msg(sb, KERN_INFO,
@@ -452,6 +462,10 @@ static int parse_options(struct super_block *sb, char *options)
                        f2fs_msg(sb, KERN_INFO,
                                "inline_xattr options not supported");
                        break;
+               case Opt_noinline_xattr:
+                       f2fs_msg(sb, KERN_INFO,
+                               "noinline_xattr options not supported");
+                       break;
 #endif
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
                case Opt_acl:
@@ -535,11 +549,23 @@ static int parse_options(struct super_block *sb, char *options)
                        }
                        kfree(name);
                        break;
+               case Opt_io_size_bits:
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+                       if (arg > __ilog2_u32(BIO_MAX_PAGES)) {
+                               f2fs_msg(sb, KERN_WARNING,
+                                       "Not support %d, larger than %d",
+                                       1 << arg, BIO_MAX_PAGES);
+                               return -EINVAL;
+                       }
+                       sbi->write_io_size_bits = arg;
+                       break;
                case Opt_fault_injection:
                        if (args->from && match_int(args, &arg))
                                return -EINVAL;
 #ifdef CONFIG_F2FS_FAULT_INJECTION
                        f2fs_build_fault_attr(sbi, arg);
+                       set_opt(sbi, FAULT_INJECTION);
 #else
                        f2fs_msg(sb, KERN_INFO,
                                "FAULT_INJECTION was not selected");
@@ -558,6 +584,13 @@ static int parse_options(struct super_block *sb, char *options)
                        return -EINVAL;
                }
        }
+
+       if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
+               f2fs_msg(sb, KERN_ERR,
+                               "Should set mode=lfs with %uKB-sized IO",
+                               F2FS_IO_SIZE_KB(sbi));
+               return -EINVAL;
+       }
        return 0;
 }
 
@@ -591,6 +624,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
 
 static int f2fs_drop_inode(struct inode *inode)
 {
+       int ret;
        /*
         * This is to avoid a deadlock condition like below.
         * writeback_single_inode(inode)
@@ -623,10 +657,12 @@ static int f2fs_drop_inode(struct inode *inode)
                        spin_lock(&inode->i_lock);
                        atomic_dec(&inode->i_count);
                }
+               trace_f2fs_drop_inode(inode, 0);
                return 0;
        }
-
-       return generic_drop_inode(inode);
+       ret = generic_drop_inode(inode);
+       trace_f2fs_drop_inode(inode, ret);
+       return ret;
 }
 
 int f2fs_inode_dirtied(struct inode *inode, bool sync)
@@ -750,6 +786,9 @@ static void f2fs_put_super(struct super_block *sb)
                write_checkpoint(sbi, &cpc);
        }
 
+       /* be sure to wait for any on-going discard commands */
+       f2fs_wait_discard_bio(sbi, NULL_ADDR);
+
        /* write_checkpoint can update stat informaion */
        f2fs_destroy_stats(sbi);
 
@@ -782,7 +821,7 @@ static void f2fs_put_super(struct super_block *sb)
        kfree(sbi->raw_super);
 
        destroy_device_list(sbi);
-
+       mempool_destroy(sbi->write_io_dummy);
        destroy_percpu_info(sbi);
        kfree(sbi);
 }
@@ -882,6 +921,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_puts(seq, ",nouser_xattr");
        if (test_opt(sbi, INLINE_XATTR))
                seq_puts(seq, ",inline_xattr");
+       else
+               seq_puts(seq, ",noinline_xattr");
 #endif
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
        if (test_opt(sbi, POSIX_ACL))
@@ -918,6 +959,12 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
        else if (test_opt(sbi, LFS))
                seq_puts(seq, "lfs");
        seq_printf(seq, ",active_logs=%u", sbi->active_logs);
+       if (F2FS_IO_SIZE_BITS(sbi))
+               seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
+#ifdef CONFIG_F2FS_FAULT_INJECTION
+       if (test_opt(sbi, FAULT_INJECTION))
+               seq_puts(seq, ",fault_injection");
+#endif
 
        return 0;
 }
@@ -995,6 +1042,7 @@ static void default_options(struct f2fs_sb_info *sbi)
        sbi->active_logs = NR_CURSEG_TYPE;
 
        set_opt(sbi, BG_GC);
+       set_opt(sbi, INLINE_XATTR);
        set_opt(sbi, INLINE_DATA);
        set_opt(sbi, INLINE_DENTRY);
        set_opt(sbi, EXTENT_CACHE);
@@ -1686,36 +1734,55 @@ int f2fs_commit_super(struct f2fs_sb_info *sbi, bool recover)
 static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
 {
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
+       unsigned int max_devices = MAX_DEVICES;
        int i;
 
-       for (i = 0; i < MAX_DEVICES; i++) {
-               if (!RDEV(i).path[0])
+       /* Initialize single device information */
+       if (!RDEV(0).path[0]) {
+               if (!bdev_is_zoned(sbi->sb->s_bdev))
                        return 0;
+               max_devices = 1;
+       }
 
-               if (i == 0) {
-                       sbi->devs = kzalloc(sizeof(struct f2fs_dev_info) *
-                                               MAX_DEVICES, GFP_KERNEL);
-                       if (!sbi->devs)
-                               return -ENOMEM;
-               }
+       /*
+        * Initialize multiple devices information, or single
+        * zoned block device information.
+        */
+       sbi->devs = kcalloc(max_devices, sizeof(struct f2fs_dev_info),
+                               GFP_KERNEL);
+       if (!sbi->devs)
+               return -ENOMEM;
 
-               memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN);
-               FDEV(i).total_segments = le32_to_cpu(RDEV(i).total_segments);
-               if (i == 0) {
-                       FDEV(i).start_blk = 0;
-                       FDEV(i).end_blk = FDEV(i).start_blk +
-                               (FDEV(i).total_segments <<
-                               sbi->log_blocks_per_seg) - 1 +
-                               le32_to_cpu(raw_super->segment0_blkaddr);
-               } else {
-                       FDEV(i).start_blk = FDEV(i - 1).end_blk + 1;
-                       FDEV(i).end_blk = FDEV(i).start_blk +
-                               (FDEV(i).total_segments <<
-                               sbi->log_blocks_per_seg) - 1;
-               }
+       for (i = 0; i < max_devices; i++) {
 
-               FDEV(i).bdev = blkdev_get_by_path(FDEV(i).path,
+               if (i > 0 && !RDEV(i).path[0])
+                       break;
+
+               if (max_devices == 1) {
+                       /* Single zoned block device mount */
+                       FDEV(0).bdev =
+                               blkdev_get_by_dev(sbi->sb->s_bdev->bd_dev,
+                                       sbi->sb->s_mode, sbi->sb->s_type);
+               } else {
+                       /* Multi-device mount */
+                       memcpy(FDEV(i).path, RDEV(i).path, MAX_PATH_LEN);
+                       FDEV(i).total_segments =
+                               le32_to_cpu(RDEV(i).total_segments);
+                       if (i == 0) {
+                               FDEV(i).start_blk = 0;
+                               FDEV(i).end_blk = FDEV(i).start_blk +
+                                   (FDEV(i).total_segments <<
+                                   sbi->log_blocks_per_seg) - 1 +
+                                   le32_to_cpu(raw_super->segment0_blkaddr);
+                       } else {
+                               FDEV(i).start_blk = FDEV(i - 1).end_blk + 1;
+                               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,
                                        sbi->sb->s_mode, sbi->sb->s_type);
+               }
                if (IS_ERR(FDEV(i).bdev))
                        return PTR_ERR(FDEV(i).bdev);
 
@@ -1735,6 +1802,8 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
                                        "Failed to initialize F2FS blkzone information");
                                return -EINVAL;
                        }
+                       if (max_devices == 1)
+                               break;
                        f2fs_msg(sbi->sb, KERN_INFO,
                                "Mount Device [%2d]: %20s, %8u, %8x - %8x (zone: %s)",
                                i, FDEV(i).path,
@@ -1751,6 +1820,8 @@ static int f2fs_scan_devices(struct f2fs_sb_info *sbi)
                                FDEV(i).total_segments,
                                FDEV(i).start_blk, FDEV(i).end_blk);
        }
+       f2fs_msg(sbi->sb, KERN_INFO,
+                       "IO Block Size: %8d KB", F2FS_IO_SIZE_KB(sbi));
        return 0;
 }
 
@@ -1868,12 +1939,19 @@ try_onemore:
        if (err)
                goto free_options;
 
+       if (F2FS_IO_SIZE(sbi) > 1) {
+               sbi->write_io_dummy =
+                       mempool_create_page_pool(2 * (F2FS_IO_SIZE(sbi) - 1), 0);
+               if (!sbi->write_io_dummy)
+                       goto free_options;
+       }
+
        /* get an inode for meta space */
        sbi->meta_inode = f2fs_iget(sb, F2FS_META_INO(sbi));
        if (IS_ERR(sbi->meta_inode)) {
                f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode");
                err = PTR_ERR(sbi->meta_inode);
-               goto free_options;
+               goto free_io_dummy;
        }
 
        err = get_valid_checkpoint(sbi);
@@ -2048,6 +2126,8 @@ skip_recovery:
                        sbi->valid_super_block ? 1 : 2, err);
        }
 
+       f2fs_msg(sbi->sb, KERN_NOTICE, "Mounted with checkpoint version = %llx",
+                               cur_cp_version(F2FS_CKPT(sbi)));
        f2fs_update_time(sbi, CP_TIME);
        f2fs_update_time(sbi, REQ_TIME);
        return 0;
@@ -2091,6 +2171,8 @@ free_devices:
 free_meta_inode:
        make_bad_inode(sbi->meta_inode);
        iput(sbi->meta_inode);
+free_io_dummy:
+       mempool_destroy(sbi->write_io_dummy);
 free_options:
        destroy_percpu_info(sbi);
        kfree(options);