f2fs: add remount_fs callback support
authorNamjae Jeon <namjae.jeon@samsung.com>
Sun, 16 Jun 2013 00:48:48 +0000 (09:48 +0900)
committerJaegeuk Kim <jaegeuk.kim@samsung.com>
Mon, 17 Jun 2013 12:17:55 +0000 (21:17 +0900)
Add the f2fs_remount function call which will be used
during the filesystem remounting. This function
will help us to change the mount options specific to
f2fs.

Also modify the f2fs background_gc mount option, which
will allow the user to dynamically trun on/off the
garbage collection in f2fs based on the background_gc
value. If background_gc=on, Garbage collection will
be turned off & if background_gc=off, Garbage collection
will be truned on.

By default the garbage collection is on in f2fs.

Change Log:
v2: Incorporated the review comments by Gu Zheng.
    Removing the restore part for VFS flags
    Updating comments with proper flag conditions
    Display GC background option as ON/OFF
    Revised conditions to stop GC in case of remount

v1: Initial changes for adding remount_fs callback
support.

Cc: Gu Zheng <guz.fnst@cn.fujitsu.com>
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Pankaj Kumar <pankaj.km@samsung.com>
Reviewed-by: Gu Zheng <guz.fnst@cn.fujitsu.com>
[Jaegeuk Kim: change /** with /* for the coding style]
Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Documentation/filesystems/f2fs.txt
fs/f2fs/super.c

index bd3c56c..b91e2f2 100644 (file)
@@ -98,8 +98,13 @@ Cleaning Overhead
 MOUNT OPTIONS
 ================================================================================
 
-background_gc_off      Turn off cleaning operations, namely garbage collection,
-                      triggered in background when I/O subsystem is idle.
+background_gc=%s       Turn on/off cleaning operations, namely garbage
+                       collection, triggered in background when I/O subsystem is
+                       idle. If background_gc=on, it will turn on the garbage
+                       collection and if background_gc=off, garbage collection
+                       will be truned off.
+                       Default value for this option is on. So garbage
+                       collection is on by default.
 disable_roll_forward   Disable the roll-forward recovery routine
 discard                Issue discard/TRIM commands when a segment is cleaned.
 no_heap                Disable heap-style segment allocation which finds free
index ba56549..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;
@@ -225,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))
@@ -255,6 +340,58 @@ 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,
@@ -268,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,
@@ -315,79 +453,6 @@ static const struct export_operations f2fs_export_ops = {
        .get_parent = f2fs_get_parent,
 };
 
-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;
-       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;
@@ -686,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)