Merge branch 'sched-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[firefly-linux-kernel-4.4.55.git] / fs / f2fs / super.c
index 84f95cd4076a8742a47f53644263f93df7833ccd..f2fe666a6ea995a29d5aee3f228acaf75e6cf85a 100644 (file)
@@ -42,6 +42,7 @@ static struct kset *f2fs_kset;
 enum {
        Opt_gc_background,
        Opt_disable_roll_forward,
+       Opt_norecovery,
        Opt_discard,
        Opt_noheap,
        Opt_user_xattr,
@@ -62,6 +63,7 @@ enum {
 static match_table_t f2fs_tokens = {
        {Opt_gc_background, "background_gc=%s"},
        {Opt_disable_roll_forward, "disable_roll_forward"},
+       {Opt_norecovery, "norecovery"},
        {Opt_discard, "discard"},
        {Opt_noheap, "no_heap"},
        {Opt_user_xattr, "user_xattr"},
@@ -193,6 +195,7 @@ 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(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);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks);
@@ -208,6 +211,7 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(gc_idle),
        ATTR_LIST(reclaim_segments),
        ATTR_LIST(max_small_discards),
+       ATTR_LIST(batched_trim_sections),
        ATTR_LIST(ipu_policy),
        ATTR_LIST(min_ipu_util),
        ATTR_LIST(min_fsync_blocks),
@@ -287,6 +291,12 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_disable_roll_forward:
                        set_opt(sbi, DISABLE_ROLL_FORWARD);
                        break;
+               case Opt_norecovery:
+                       /* this option mounts f2fs with ro */
+                       set_opt(sbi, DISABLE_ROLL_FORWARD);
+                       if (!f2fs_readonly(sb))
+                               return -EINVAL;
+                       break;
                case Opt_discard:
                        set_opt(sbi, DISCARD);
                        break;
@@ -447,8 +457,13 @@ static void f2fs_put_super(struct super_block *sb)
        f2fs_destroy_stats(sbi);
        stop_gc_thread(sbi);
 
-       /* We don't need to do checkpoint when it's clean */
-       if (sbi->s_dirty) {
+       /*
+        * We don't need to do checkpoint when superblock is clean.
+        * But, the previous checkpoint was not done by umount, it needs to do
+        * clean checkpoint again.
+        */
+       if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) ||
+                       !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) {
                struct cp_control cpc = {
                        .reason = CP_UMOUNT,
                };
@@ -487,8 +502,8 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
        if (sync) {
                struct cp_control cpc;
 
-               cpc.reason = (test_opt(sbi, FASTBOOT) || sbi->s_closing) ?
-                                                       CP_UMOUNT : CP_SYNC;
+               cpc.reason = __get_cp_reason(sbi);
+
                mutex_lock(&sbi->gc_mutex);
                write_checkpoint(sbi, &cpc);
                mutex_unlock(&sbi->gc_mutex);
@@ -890,7 +905,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
                atomic_set(&sbi->nr_pages[i], 0);
 
        sbi->dir_level = DEF_DIR_LEVEL;
-       sbi->need_fsck = false;
+       clear_sbi_flag(sbi, SBI_NEED_FSCK);
 }
 
 /*
@@ -945,6 +960,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        struct inode *root;
        long err = -EINVAL;
        bool retry = true;
+       char *options = NULL;
        int i;
 
 try_onemore:
@@ -976,9 +992,15 @@ try_onemore:
        set_opt(sbi, POSIX_ACL);
 #endif
        /* parse mount options */
-       err = parse_options(sb, (char *)data);
-       if (err)
+       options = kstrdup((const char *)data, GFP_KERNEL);
+       if (data && !options) {
+               err = -ENOMEM;
                goto free_sb_buf;
+       }
+
+       err = parse_options(sb, options);
+       if (err)
+               goto free_options;
 
        sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize));
        sb->s_max_links = F2FS_LINK_MAX;
@@ -1001,7 +1023,7 @@ try_onemore:
        mutex_init(&sbi->writepages);
        mutex_init(&sbi->cp_mutex);
        init_rwsem(&sbi->node_write);
-       sbi->por_doing = false;
+       clear_sbi_flag(sbi, SBI_POR_DOING);
        spin_lock_init(&sbi->stat_lock);
 
        init_rwsem(&sbi->read_io.io_rwsem);
@@ -1022,7 +1044,7 @@ try_onemore:
        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_sb_buf;
+               goto free_options;
        }
 
        err = get_valid_checkpoint(sbi);
@@ -1125,10 +1147,19 @@ try_onemore:
                goto free_proc;
 
        if (!retry)
-               sbi->need_fsck = true;
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
 
        /* recover fsynced data */
        if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
+               /*
+                * mount should be failed, when device has readonly mode, and
+                * previous checkpoint was not done by clean system shutdown.
+                */
+               if (bdev_read_only(sb->s_bdev) &&
+                               !is_set_ckpt_flags(sbi->ckpt, CP_UMOUNT_FLAG)) {
+                       err = -EROFS;
+                       goto free_kobj;
+               }
                err = recover_fsync_data(sbi);
                if (err) {
                        f2fs_msg(sb, KERN_ERR,
@@ -1147,6 +1178,7 @@ try_onemore:
                if (err)
                        goto free_kobj;
        }
+       kfree(options);
        return 0;
 
 free_kobj:
@@ -1171,6 +1203,8 @@ free_cp:
 free_meta_inode:
        make_bad_inode(sbi->meta_inode);
        iput(sbi->meta_inode);
+free_options:
+       kfree(options);
 free_sb_buf:
        brelse(raw_super_buf);
 free_sbi:
@@ -1194,7 +1228,7 @@ static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags,
 static void kill_f2fs_super(struct super_block *sb)
 {
        if (sb->s_root)
-               F2FS_SB(sb)->s_closing = true;
+               set_sbi_flag(F2FS_SB(sb), SBI_IS_CLOSE);
        kill_block_super(sb);
 }