Merge branch 'kconfig-diet' from Dave Hansen
[cascardo/linux.git] / fs / f2fs / super.c
index 8555f7d..75c7dc3 100644 (file)
@@ -34,7 +34,7 @@
 static struct kmem_cache *f2fs_inode_cachep;
 
 enum {
-       Opt_gc_background_off,
+       Opt_gc_background,
        Opt_disable_roll_forward,
        Opt_discard,
        Opt_noheap,
@@ -46,7 +46,7 @@ enum {
 };
 
 static match_table_t f2fs_tokens = {
-       {Opt_gc_background_off, "background_gc_off"},
+       {Opt_gc_background, "background_gc=%s"},
        {Opt_disable_roll_forward, "disable_roll_forward"},
        {Opt_discard, "discard"},
        {Opt_noheap, "no_heap"},
@@ -76,6 +76,91 @@ static void init_once(void *foo)
        inode_init_once(&fi->vfs_inode);
 }
 
+static int parse_options(struct super_block *sb, char *options)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       substring_t args[MAX_OPT_ARGS];
+       char *p, *name;
+       int arg = 0;
+
+       if (!options)
+               return 0;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+               /*
+                * Initialize args struct so we know whether arg was
+                * found; some options take optional arguments.
+                */
+               args[0].to = args[0].from = NULL;
+               token = match_token(p, f2fs_tokens, args);
+
+               switch (token) {
+               case Opt_gc_background:
+                       name = match_strdup(&args[0]);
+
+                       if (!name)
+                               return -ENOMEM;
+                       if (!strncmp(name, "on", 2))
+                               set_opt(sbi, BG_GC);
+                       else if (!strncmp(name, "off", 3))
+                               clear_opt(sbi, BG_GC);
+                       else {
+                               kfree(name);
+                               return -EINVAL;
+                       }
+                       kfree(name);
+                       break;
+               case Opt_disable_roll_forward:
+                       set_opt(sbi, DISABLE_ROLL_FORWARD);
+                       break;
+               case Opt_discard:
+                       set_opt(sbi, DISCARD);
+                       break;
+               case Opt_noheap:
+                       set_opt(sbi, NOHEAP);
+                       break;
+#ifdef CONFIG_F2FS_FS_XATTR
+               case Opt_nouser_xattr:
+                       clear_opt(sbi, XATTR_USER);
+                       break;
+#else
+               case Opt_nouser_xattr:
+                       f2fs_msg(sb, KERN_INFO,
+                               "nouser_xattr options not supported");
+                       break;
+#endif
+#ifdef CONFIG_F2FS_FS_POSIX_ACL
+               case Opt_noacl:
+                       clear_opt(sbi, POSIX_ACL);
+                       break;
+#else
+               case Opt_noacl:
+                       f2fs_msg(sb, KERN_INFO, "noacl options not supported");
+                       break;
+#endif
+               case Opt_active_logs:
+                       if (args->from && match_int(args, &arg))
+                               return -EINVAL;
+                       if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE)
+                               return -EINVAL;
+                       sbi->active_logs = arg;
+                       break;
+               case Opt_disable_ext_identify:
+                       set_opt(sbi, DISABLE_EXT_IDENTIFY);
+                       break;
+               default:
+                       f2fs_msg(sb, KERN_ERR,
+                               "Unrecognized mount option \"%s\" or missing value",
+                               p);
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 static struct inode *f2fs_alloc_inode(struct super_block *sb)
 {
        struct f2fs_inode_info *fi;
@@ -112,6 +197,17 @@ static int f2fs_drop_inode(struct inode *inode)
        return generic_drop_inode(inode);
 }
 
+/*
+ * f2fs_dirty_inode() is called from __mark_inode_dirty()
+ *
+ * We should call set_dirty_inode to write the dirty inode through write_inode.
+ */
+static void f2fs_dirty_inode(struct inode *inode, int flags)
+{
+       set_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
+       return;
+}
+
 static void f2fs_i_callback(struct rcu_head *head)
 {
        struct inode *inode = container_of(head, struct inode, i_rcu);
@@ -170,7 +266,7 @@ static int f2fs_freeze(struct super_block *sb)
 {
        int err;
 
-       if (sb->s_flags & MS_RDONLY)
+       if (f2fs_readonly(sb))
                return 0;
 
        err = f2fs_sync_fs(sb, 1);
@@ -214,10 +310,10 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);
 
-       if (test_opt(sbi, BG_GC))
-               seq_puts(seq, ",background_gc_on");
+       if (!(root->d_sb->s_flags & MS_RDONLY) && test_opt(sbi, BG_GC))
+               seq_printf(seq, ",background_gc=%s", "on");
        else
-               seq_puts(seq, ",background_gc_off");
+               seq_printf(seq, ",background_gc=%s", "off");
        if (test_opt(sbi, DISABLE_ROLL_FORWARD))
                seq_puts(seq, ",disable_roll_forward");
        if (test_opt(sbi, DISCARD))
@@ -244,11 +340,64 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
        return 0;
 }
 
+static int f2fs_remount(struct super_block *sb, int *flags, char *data)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       struct f2fs_mount_info org_mount_opt;
+       int err, active_logs;
+
+       /*
+        * Save the old mount options in case we
+        * need to restore them.
+        */
+       org_mount_opt = sbi->mount_opt;
+       active_logs = sbi->active_logs;
+
+       /* parse mount options */
+       err = parse_options(sb, data);
+       if (err)
+               goto restore_opts;
+
+       /*
+        * Previous and new state of filesystem is RO,
+        * so no point in checking GC conditions.
+        */
+       if ((sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY))
+               goto skip;
+
+       /*
+        * We stop the GC thread if FS is mounted as RO
+        * or if background_gc = off is passed in mount
+        * option. Also sync the filesystem.
+        */
+       if ((*flags & MS_RDONLY) || !test_opt(sbi, BG_GC)) {
+               if (sbi->gc_thread) {
+                       stop_gc_thread(sbi);
+                       f2fs_sync_fs(sb, 1);
+               }
+       } else if (test_opt(sbi, BG_GC) && !sbi->gc_thread) {
+               err = start_gc_thread(sbi);
+               if (err)
+                       goto restore_opts;
+       }
+skip:
+       /* Update the POSIXACL Flag */
+        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+               (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
+       return 0;
+
+restore_opts:
+       sbi->mount_opt = org_mount_opt;
+       sbi->active_logs = active_logs;
+       return err;
+}
+
 static struct super_operations f2fs_sops = {
        .alloc_inode    = f2fs_alloc_inode,
        .drop_inode     = f2fs_drop_inode,
        .destroy_inode  = f2fs_destroy_inode,
        .write_inode    = f2fs_write_inode,
+       .dirty_inode    = f2fs_dirty_inode,
        .show_options   = f2fs_show_options,
        .evict_inode    = f2fs_evict_inode,
        .put_super      = f2fs_put_super,
@@ -256,6 +405,7 @@ static struct super_operations f2fs_sops = {
        .freeze_fs      = f2fs_freeze,
        .unfreeze_fs    = f2fs_unfreeze,
        .statfs         = f2fs_statfs,
+       .remount_fs     = f2fs_remount,
 };
 
 static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
@@ -303,79 +453,6 @@ static const struct export_operations f2fs_export_ops = {
        .get_parent = f2fs_get_parent,
 };
 
-static int parse_options(struct super_block *sb, struct f2fs_sb_info *sbi,
-                               char *options)
-{
-       substring_t args[MAX_OPT_ARGS];
-       char *p;
-       int arg = 0;
-
-       if (!options)
-               return 0;
-
-       while ((p = strsep(&options, ",")) != NULL) {
-               int token;
-               if (!*p)
-                       continue;
-               /*
-                * Initialize args struct so we know whether arg was
-                * found; some options take optional arguments.
-                */
-               args[0].to = args[0].from = NULL;
-               token = match_token(p, f2fs_tokens, args);
-
-               switch (token) {
-               case Opt_gc_background_off:
-                       clear_opt(sbi, BG_GC);
-                       break;
-               case Opt_disable_roll_forward:
-                       set_opt(sbi, DISABLE_ROLL_FORWARD);
-                       break;
-               case Opt_discard:
-                       set_opt(sbi, DISCARD);
-                       break;
-               case Opt_noheap:
-                       set_opt(sbi, NOHEAP);
-                       break;
-#ifdef CONFIG_F2FS_FS_XATTR
-               case Opt_nouser_xattr:
-                       clear_opt(sbi, XATTR_USER);
-                       break;
-#else
-               case Opt_nouser_xattr:
-                       f2fs_msg(sb, KERN_INFO,
-                               "nouser_xattr options not supported");
-                       break;
-#endif
-#ifdef CONFIG_F2FS_FS_POSIX_ACL
-               case Opt_noacl:
-                       clear_opt(sbi, POSIX_ACL);
-                       break;
-#else
-               case Opt_noacl:
-                       f2fs_msg(sb, KERN_INFO, "noacl options not supported");
-                       break;
-#endif
-               case Opt_active_logs:
-                       if (args->from && match_int(args, &arg))
-                               return -EINVAL;
-                       if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE)
-                               return -EINVAL;
-                       sbi->active_logs = arg;
-                       break;
-               case Opt_disable_ext_identify:
-                       set_opt(sbi, DISABLE_EXT_IDENTIFY);
-                       break;
-               default:
-                       f2fs_msg(sb, KERN_ERR,
-                               "Unrecognized mount option \"%s\" or missing value",
-                               p);
-                       return -EINVAL;
-               }
-       }
-       return 0;
-}
-
 static loff_t max_file_size(unsigned bits)
 {
        loff_t result = ADDRS_PER_INODE;
@@ -541,6 +618,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                if (err)
                        goto free_sb_buf;
        }
+       sb->s_fs_info = sbi;
        /* init some FS parameters */
        sbi->active_logs = NR_CURSEG_TYPE;
 
@@ -553,7 +631,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        set_opt(sbi, POSIX_ACL);
 #endif
        /* parse mount options */
-       err = parse_options(sb, sbi, (char *)data);
+       err = parse_options(sb, (char *)data);
        if (err)
                goto free_sb_buf;
 
@@ -565,7 +643,6 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_xattr = f2fs_xattr_handlers;
        sb->s_export_op = &f2fs_export_ops;
        sb->s_magic = F2FS_SUPER_MAGIC;
-       sb->s_fs_info = sbi;
        sb->s_time_gran = 1;
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                (test_opt(sbi, POSIX_ACL) ? MS_POSIXACL : 0);
@@ -674,10 +751,16 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                                "Cannot recover all fsync data errno=%ld", err);
        }
 
-       /* After POR, we can run background GC thread */
-       err = start_gc_thread(sbi);
-       if (err)
-               goto fail;
+       /*
+        * 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 fail;
+       }
 
        err = f2fs_build_stats(sbi);
        if (err)