]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - fs/f2fs/super.c
Merge tag 'for-f2fs-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk...
[karo-tx-linux.git] / fs / f2fs / super.c
index 856bdf994c0a4262f802bf3fdf2fa3ed7b8167c7..c756923a7302cc6dc144e108a11a4d2ceb5800ed 100644 (file)
@@ -51,6 +51,7 @@ enum {
        Opt_disable_ext_identify,
        Opt_inline_xattr,
        Opt_inline_data,
+       Opt_flush_merge,
        Opt_err,
 };
 
@@ -67,6 +68,7 @@ static match_table_t f2fs_tokens = {
        {Opt_disable_ext_identify, "disable_ext_identify"},
        {Opt_inline_xattr, "inline_xattr"},
        {Opt_inline_data, "inline_data"},
+       {Opt_flush_merge, "flush_merge"},
        {Opt_err, NULL},
 };
 
@@ -74,6 +76,7 @@ static match_table_t f2fs_tokens = {
 enum {
        GC_THREAD,      /* struct f2fs_gc_thread */
        SM_INFO,        /* struct f2fs_sm_info */
+       NM_INFO,        /* struct f2fs_nm_info */
        F2FS_SBI,       /* struct f2fs_sb_info */
 };
 
@@ -92,6 +95,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 == NM_INFO)
+               return (unsigned char *)NM_I(sbi);
        else if (struct_type == F2FS_SBI)
                return (unsigned char *)sbi;
        return NULL;
@@ -183,7 +188,9 @@ 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, ipu_policy, ipu_policy);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
+F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
@@ -196,6 +203,8 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(ipu_policy),
        ATTR_LIST(min_ipu_util),
        ATTR_LIST(max_victim_search),
+       ATTR_LIST(dir_level),
+       ATTR_LIST(ram_thresh),
        NULL,
 };
 
@@ -256,9 +265,9 @@ static int parse_options(struct super_block *sb, char *options)
 
                        if (!name)
                                return -ENOMEM;
-                       if (!strncmp(name, "on", 2))
+                       if (strlen(name) == 2 && !strncmp(name, "on", 2))
                                set_opt(sbi, BG_GC);
-                       else if (!strncmp(name, "off", 3))
+                       else if (strlen(name) == 3 && !strncmp(name, "off", 3))
                                clear_opt(sbi, BG_GC);
                        else {
                                kfree(name);
@@ -327,6 +336,9 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_inline_data:
                        set_opt(sbi, INLINE_DATA);
                        break;
+               case Opt_flush_merge:
+                       set_opt(sbi, FLUSH_MERGE);
+                       break;
                default:
                        f2fs_msg(sb, KERN_ERR,
                                "Unrecognized mount option \"%s\" or missing value",
@@ -353,12 +365,16 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
        fi->i_current_depth = 1;
        fi->i_advise = 0;
        rwlock_init(&fi->ext.ext_lock);
+       init_rwsem(&fi->i_sem);
 
        set_inode_flag(fi, FI_NEW_INODE);
 
        if (test_opt(F2FS_SB(sb), INLINE_XATTR))
                set_inode_flag(fi, FI_INLINE_XATTR);
 
+       /* Will be used by directory only */
+       fi->i_dir_level = F2FS_SB(sb)->dir_level;
+
        return &fi->vfs_inode;
 }
 
@@ -526,6 +542,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_puts(seq, ",disable_ext_identify");
        if (test_opt(sbi, INLINE_DATA))
                seq_puts(seq, ",inline_data");
+       if (test_opt(sbi, FLUSH_MERGE))
+               seq_puts(seq, ",flush_merge");
        seq_printf(seq, ",active_logs=%u", sbi->active_logs);
 
        return 0;
@@ -539,13 +557,22 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset)
                        le32_to_cpu(sbi->raw_super->segment_count_main);
        int i;
 
+       seq_puts(seq, "format: segment_type|valid_blocks\n"
+               "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");
+
        for (i = 0; i < total_segs; i++) {
-               seq_printf(seq, "%u", get_valid_blocks(sbi, i, 1));
-               if (i != 0 && (i % 10) == 0)
-                       seq_puts(seq, "\n");
+               struct seg_entry *se = get_seg_entry(sbi, i);
+
+               if ((i % 10) == 0)
+                       seq_printf(seq, "%-5d", i);
+               seq_printf(seq, "%d|%-3u", se->type,
+                                       get_valid_blocks(sbi, i, 1));
+               if ((i % 10) == 9 || i == (total_segs - 1))
+                       seq_putc(seq, '\n');
                else
-                       seq_puts(seq, " ");
+                       seq_putc(seq, ' ');
        }
+
        return 0;
 }
 
@@ -640,6 +667,8 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
 
        if (unlikely(ino < F2FS_ROOT_INO(sbi)))
                return ERR_PTR(-ESTALE);
+       if (unlikely(ino >= NM_I(sbi)->max_nid))
+               return ERR_PTR(-ESTALE);
 
        /*
         * f2fs_iget isn't quite right if the inode is currently unallocated!
@@ -787,6 +816,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
 
        for (i = 0; i < NR_COUNT_TYPE; i++)
                atomic_set(&sbi->nr_pages[i], 0);
+
+       sbi->dir_level = DEF_DIR_LEVEL;
 }
 
 /*
@@ -898,11 +929,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        sbi->por_doing = false;
        spin_lock_init(&sbi->stat_lock);
 
-       mutex_init(&sbi->read_io.io_mutex);
+       init_rwsem(&sbi->read_io.io_rwsem);
        sbi->read_io.sbi = sbi;
        sbi->read_io.bio = NULL;
        for (i = 0; i < NR_PAGE_TYPE; i++) {
-               mutex_init(&sbi->write_io[i].io_mutex);
+               init_rwsem(&sbi->write_io[i].io_rwsem);
                sbi->write_io[i].sbi = sbi;
                sbi->write_io[i].bio = NULL;
        }
@@ -991,28 +1022,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_root_inode;
        }
 
-       /* recover fsynced data */
-       if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
-               err = recover_fsync_data(sbi);
-               if (err)
-                       f2fs_msg(sb, KERN_ERR,
-                               "Cannot recover all fsync data errno=%ld", err);
-       }
-
-       /*
-        * If filesystem is not mounted as read-only then
-        * do start the gc_thread.
-        */
-       if (!(sb->s_flags & MS_RDONLY)) {
-               /* After POR, we can run background GC thread.*/
-               err = start_gc_thread(sbi);
-               if (err)
-                       goto free_gc;
-       }
-
        err = f2fs_build_stats(sbi);
        if (err)
-               goto free_gc;
+               goto free_root_inode;
 
        if (f2fs_proc_root)
                sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
@@ -1034,17 +1046,36 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        err = kobject_init_and_add(&sbi->s_kobj, &f2fs_ktype, NULL,
                                                        "%s", sb->s_id);
        if (err)
-               goto fail;
+               goto free_proc;
+
+       /* recover fsynced data */
+       if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
+               err = recover_fsync_data(sbi);
+               if (err)
+                       f2fs_msg(sb, KERN_ERR,
+                               "Cannot recover all fsync data errno=%ld", err);
+       }
 
+       /*
+        * If filesystem is not mounted as read-only then
+        * do start the gc_thread.
+        */
+       if (!(sb->s_flags & MS_RDONLY)) {
+               /* After POR, we can run background GC thread.*/
+               err = start_gc_thread(sbi);
+               if (err)
+                       goto free_kobj;
+       }
        return 0;
-fail:
+
+free_kobj:
+       kobject_del(&sbi->s_kobj);
+free_proc:
        if (sbi->s_proc) {
                remove_proc_entry("segment_info", sbi->s_proc);
                remove_proc_entry(sb->s_id, f2fs_proc_root);
        }
        f2fs_destroy_stats(sbi);
-free_gc:
-       stop_gc_thread(sbi);
 free_root_inode:
        dput(sb->s_root);
        sb->s_root = NULL;
@@ -1084,7 +1115,7 @@ MODULE_ALIAS_FS("f2fs");
 static int __init init_inodecache(void)
 {
        f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache",
-                       sizeof(struct f2fs_inode_info), NULL);
+                       sizeof(struct f2fs_inode_info));
        if (!f2fs_inode_cachep)
                return -ENOMEM;
        return 0;