Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[cascardo/linux.git] / fs / f2fs / super.c
index 74cc852..1b86d3f 100644 (file)
@@ -49,6 +49,7 @@ char *fault_name[FAULT_MAX] = {
        [FAULT_ORPHAN]          = "orphan",
        [FAULT_BLOCK]           = "no more block",
        [FAULT_DIR_DEPTH]       = "too big dir depth",
+       [FAULT_EVICT_INODE]     = "evict_inode fail",
 };
 
 static void f2fs_build_fault_attr(unsigned int rate)
@@ -75,6 +76,7 @@ enum {
        Opt_disable_roll_forward,
        Opt_norecovery,
        Opt_discard,
+       Opt_nodiscard,
        Opt_noheap,
        Opt_user_xattr,
        Opt_nouser_xattr,
@@ -86,13 +88,17 @@ enum {
        Opt_inline_data,
        Opt_inline_dentry,
        Opt_flush_merge,
+       Opt_noflush_merge,
        Opt_nobarrier,
        Opt_fastboot,
        Opt_extent_cache,
        Opt_noextent_cache,
        Opt_noinline_data,
        Opt_data_flush,
+       Opt_mode,
        Opt_fault_injection,
+       Opt_lazytime,
+       Opt_nolazytime,
        Opt_err,
 };
 
@@ -101,6 +107,7 @@ static match_table_t f2fs_tokens = {
        {Opt_disable_roll_forward, "disable_roll_forward"},
        {Opt_norecovery, "norecovery"},
        {Opt_discard, "discard"},
+       {Opt_nodiscard, "nodiscard"},
        {Opt_noheap, "no_heap"},
        {Opt_user_xattr, "user_xattr"},
        {Opt_nouser_xattr, "nouser_xattr"},
@@ -112,13 +119,17 @@ static match_table_t f2fs_tokens = {
        {Opt_inline_data, "inline_data"},
        {Opt_inline_dentry, "inline_dentry"},
        {Opt_flush_merge, "flush_merge"},
+       {Opt_noflush_merge, "noflush_merge"},
        {Opt_nobarrier, "nobarrier"},
        {Opt_fastboot, "fastboot"},
        {Opt_extent_cache, "extent_cache"},
        {Opt_noextent_cache, "noextent_cache"},
        {Opt_noinline_data, "noinline_data"},
        {Opt_data_flush, "data_flush"},
+       {Opt_mode, "mode=%s"},
        {Opt_fault_injection, "fault_injection=%u"},
+       {Opt_lazytime, "lazytime"},
+       {Opt_nolazytime, "nolazytime"},
        {Opt_err, NULL},
 };
 
@@ -417,6 +428,8 @@ static int parse_options(struct super_block *sb, char *options)
                                        "the device does not support discard");
                        }
                        break;
+               case Opt_nodiscard:
+                       clear_opt(sbi, DISCARD);
                case Opt_noheap:
                        set_opt(sbi, NOHEAP);
                        break;
@@ -478,6 +491,9 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_flush_merge:
                        set_opt(sbi, FLUSH_MERGE);
                        break;
+               case Opt_noflush_merge:
+                       clear_opt(sbi, FLUSH_MERGE);
+                       break;
                case Opt_nobarrier:
                        set_opt(sbi, NOBARRIER);
                        break;
@@ -496,6 +512,23 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_data_flush:
                        set_opt(sbi, DATA_FLUSH);
                        break;
+               case Opt_mode:
+                       name = match_strdup(&args[0]);
+
+                       if (!name)
+                               return -ENOMEM;
+                       if (strlen(name) == 8 &&
+                                       !strncmp(name, "adaptive", 8)) {
+                               set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE);
+                       } else if (strlen(name) == 3 &&
+                                       !strncmp(name, "lfs", 3)) {
+                               set_opt_mode(sbi, F2FS_MOUNT_LFS);
+                       } else {
+                               kfree(name);
+                               return -EINVAL;
+                       }
+                       kfree(name);
+                       break;
                case Opt_fault_injection:
                        if (args->from && match_int(args, &arg))
                                return -EINVAL;
@@ -506,6 +539,12 @@ static int parse_options(struct super_block *sb, char *options)
                                "FAULT_INJECTION was not selected");
 #endif
                        break;
+               case Opt_lazytime:
+                       sb->s_flags |= MS_LAZYTIME;
+                       break;
+               case Opt_nolazytime:
+                       sb->s_flags &= ~MS_LAZYTIME;
+                       break;
                default:
                        f2fs_msg(sb, KERN_ERR,
                                "Unrecognized mount option \"%s\" or missing value",
@@ -537,13 +576,11 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
        fi->i_advise = 0;
        init_rwsem(&fi->i_sem);
        INIT_LIST_HEAD(&fi->dirty_list);
+       INIT_LIST_HEAD(&fi->gdirty_list);
        INIT_LIST_HEAD(&fi->inmem_pages);
        mutex_init(&fi->inmem_lock);
-
-       set_inode_flag(fi, FI_NEW_INODE);
-
-       if (test_opt(F2FS_SB(sb), INLINE_XATTR))
-               set_inode_flag(fi, FI_INLINE_XATTR);
+       init_rwsem(&fi->dio_rwsem[READ]);
+       init_rwsem(&fi->dio_rwsem[WRITE]);
 
        /* Will be used by directory only */
        fi->i_dir_level = F2FS_SB(sb)->dir_level;
@@ -559,7 +596,7 @@ static int f2fs_drop_inode(struct inode *inode)
         *    - f2fs_gc -> iput -> evict
         *       - inode_wait_for_writeback(inode)
         */
-       if (!inode_unhashed(inode) && inode->i_state & I_SYNC) {
+       if ((!inode_unhashed(inode) && inode->i_state & I_SYNC)) {
                if (!inode->i_nlink && !is_bad_inode(inode)) {
                        /* to avoid evict_inode call simultaneously */
                        atomic_inc(&inode->i_count);
@@ -573,10 +610,10 @@ static int f2fs_drop_inode(struct inode *inode)
                        f2fs_destroy_extent_node(inode);
 
                        sb_start_intwrite(inode->i_sb);
-                       i_size_write(inode, 0);
+                       f2fs_i_size_write(inode, 0);
 
                        if (F2FS_HAS_BLOCKS(inode))
-                               f2fs_truncate(inode, true);
+                               f2fs_truncate(inode);
 
                        sb_end_intwrite(inode->i_sb);
 
@@ -586,9 +623,47 @@ static int f2fs_drop_inode(struct inode *inode)
                }
                return 0;
        }
+
        return generic_drop_inode(inode);
 }
 
+int f2fs_inode_dirtied(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+       spin_lock(&sbi->inode_lock[DIRTY_META]);
+       if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
+               spin_unlock(&sbi->inode_lock[DIRTY_META]);
+               return 1;
+       }
+
+       set_inode_flag(inode, FI_DIRTY_INODE);
+       list_add_tail(&F2FS_I(inode)->gdirty_list,
+                               &sbi->inode_list[DIRTY_META]);
+       inc_page_count(sbi, F2FS_DIRTY_IMETA);
+       stat_inc_dirty_inode(sbi, DIRTY_META);
+       spin_unlock(&sbi->inode_lock[DIRTY_META]);
+
+       return 0;
+}
+
+void f2fs_inode_synced(struct inode *inode)
+{
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+       spin_lock(&sbi->inode_lock[DIRTY_META]);
+       if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) {
+               spin_unlock(&sbi->inode_lock[DIRTY_META]);
+               return;
+       }
+       list_del_init(&F2FS_I(inode)->gdirty_list);
+       clear_inode_flag(inode, FI_DIRTY_INODE);
+       clear_inode_flag(inode, FI_AUTO_RECOVER);
+       dec_page_count(sbi, F2FS_DIRTY_IMETA);
+       stat_dec_dirty_inode(F2FS_I_SB(inode), DIRTY_META);
+       spin_unlock(&sbi->inode_lock[DIRTY_META]);
+}
+
 /*
  * f2fs_dirty_inode() is called from __mark_inode_dirty()
  *
@@ -596,7 +671,19 @@ static int f2fs_drop_inode(struct inode *inode)
  */
 static void f2fs_dirty_inode(struct inode *inode, int flags)
 {
-       set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+
+       if (inode->i_ino == F2FS_NODE_INO(sbi) ||
+                       inode->i_ino == F2FS_META_INO(sbi))
+               return;
+
+       if (flags == I_DIRTY_TIME)
+               return;
+
+       if (is_inode_flag_set(inode, FI_AUTO_RECOVER))
+               clear_inode_flag(inode, FI_AUTO_RECOVER);
+
+       f2fs_inode_dirtied(inode);
 }
 
 static void f2fs_i_callback(struct rcu_head *head)
@@ -619,6 +706,8 @@ static void destroy_percpu_info(struct f2fs_sb_info *sbi)
                percpu_counter_destroy(&sbi->nr_pages[i]);
        percpu_counter_destroy(&sbi->alloc_valid_block_count);
        percpu_counter_destroy(&sbi->total_valid_inode_count);
+
+       percpu_free_rwsem(&sbi->cp_rwsem);
 }
 
 static void f2fs_put_super(struct super_block *sb)
@@ -738,7 +827,7 @@ static int f2fs_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bsize = sbi->blocksize;
 
        buf->f_blocks = total_count - start_count;
-       buf->f_bfree = buf->f_blocks - valid_user_blocks(sbi) - ovp_count;
+       buf->f_bfree = user_block_count - valid_user_blocks(sbi) + ovp_count;
        buf->f_bavail = user_block_count - valid_user_blocks(sbi);
 
        buf->f_files = sbi->total_node_count - F2FS_RESERVED_NODE_NUM;
@@ -803,6 +892,12 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_puts(seq, ",noextent_cache");
        if (test_opt(sbi, DATA_FLUSH))
                seq_puts(seq, ",data_flush");
+
+       seq_puts(seq, ",mode=");
+       if (test_opt(sbi, ADAPTIVE))
+               seq_puts(seq, "adaptive");
+       else if (test_opt(sbi, LFS))
+               seq_puts(seq, "lfs");
        seq_printf(seq, ",active_logs=%u", sbi->active_logs);
 
        return 0;
@@ -866,7 +961,6 @@ static int _name##_open_fs(struct inode *inode, struct file *file)  \
 }                                                                      \
                                                                        \
 static const struct file_operations f2fs_seq_##_name##_fops = {                \
-       .owner = THIS_MODULE,                                           \
        .open = _name##_open_fs,                                        \
        .read = seq_read,                                               \
        .llseek = seq_lseek,                                            \
@@ -884,6 +978,14 @@ static void default_options(struct f2fs_sb_info *sbi)
        set_opt(sbi, BG_GC);
        set_opt(sbi, INLINE_DATA);
        set_opt(sbi, EXTENT_CACHE);
+       sbi->sb->s_flags |= MS_LAZYTIME;
+       set_opt(sbi, FLUSH_MERGE);
+       if (f2fs_sb_mounted_hmsmr(sbi->sb)) {
+               set_opt_mode(sbi, F2FS_MOUNT_LFS);
+               set_opt(sbi, DISCARD);
+       } else {
+               set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE);
+       }
 
 #ifdef CONFIG_F2FS_FS_XATTR
        set_opt(sbi, XATTR_USER);
@@ -1367,6 +1469,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
 
        INIT_LIST_HEAD(&sbi->s_list);
        mutex_init(&sbi->umount_mutex);
+       mutex_init(&sbi->wio_mutex[NODE]);
+       mutex_init(&sbi->wio_mutex[DATA]);
 
 #ifdef CONFIG_F2FS_FS_ENCRYPTION
        memcpy(sbi->key_prefix, F2FS_KEY_DESC_PREFIX,
@@ -1379,6 +1483,9 @@ static int init_percpu_info(struct f2fs_sb_info *sbi)
 {
        int i, err;
 
+       if (percpu_init_rwsem(&sbi->cp_rwsem))
+               return -ENOMEM;
+
        for (i = 0; i < NR_COUNT_TYPE; i++) {
                err = percpu_counter_init(&sbi->nr_pages[i], 0, GFP_KERNEL);
                if (err)
@@ -1530,6 +1637,8 @@ try_onemore:
                goto free_sbi;
 
        sb->s_fs_info = sbi;
+       sbi->raw_super = raw_super;
+
        default_options(sbi);
        /* parse mount options */
        options = kstrdup((const char *)data, GFP_KERNEL);
@@ -1559,10 +1668,8 @@ try_onemore:
        memcpy(sb->s_uuid, raw_super->uuid, sizeof(raw_super->uuid));
 
        /* init f2fs-specific super block info */
-       sbi->raw_super = raw_super;
        sbi->valid_super_block = valid_super_block;
        mutex_init(&sbi->gc_mutex);
-       mutex_init(&sbi->writepages);
        mutex_init(&sbi->cp_mutex);
        init_rwsem(&sbi->node_write);
 
@@ -1579,7 +1686,6 @@ try_onemore:
                sbi->write_io[i].bio = NULL;
        }
 
-       init_rwsem(&sbi->cp_rwsem);
        init_waitqueue_head(&sbi->cp_wait);
        init_sb_info(sbi);
 
@@ -1762,6 +1868,7 @@ try_onemore:
        return 0;
 
 free_kobj:
+       f2fs_sync_inode_meta(sbi);
        kobject_del(&sbi->s_kobj);
        kobject_put(&sbi->s_kobj);
        wait_for_completion(&sbi->s_kobj_unregister);