]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
jfs: convert jfs to use the new mount api
authorEric Sandeen <sandeen@redhat.com>
Thu, 26 Sep 2024 17:19:46 +0000 (12:19 -0500)
committerChristian Brauner <brauner@kernel.org>
Tue, 8 Oct 2024 12:41:53 +0000 (14:41 +0200)
Convert the jfs filesystem to use the new mount API.
Tested by comparing random mount & remount options before and after
the change.

Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Link: https://lore.kernel.org/r/20240926171947.682881-1-sandeen@redhat.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/jfs/jfs_filsys.h
fs/jfs/super.c

index 33ef13a0b110826b9c484f5d33cfa23c4a83ded2..8794281f8ffdf09d005e646365632ff9e810ccf9 100644 (file)
@@ -24,6 +24,7 @@
 #define JFS_ERR_REMOUNT_RO 0x00000002  /* remount read-only */
 #define JFS_ERR_CONTINUE   0x00000004  /* continue */
 #define JFS_ERR_PANIC      0x00000008  /* panic */
+#define JFS_ERR_MASK      (JFS_ERR_REMOUNT_RO|JFS_ERR_CONTINUE|JFS_ERR_PANIC)
 
 /* Quota support */
 #define        JFS_USRQUOTA    0x00000010
index e1be21ca5d6efb2bbc4ff3f6b5ed74cb7bbfbd31..223d9ac59839d54282f39974e021a206bcc9c315 100644 (file)
@@ -6,11 +6,11 @@
 
 #include <linux/fs.h>
 #include <linux/module.h>
-#include <linux/parser.h>
 #include <linux/completion.h>
 #include <linux/vfs.h>
 #include <linux/quotaops.h>
-#include <linux/mount.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
 #include <linux/moduleparam.h>
 #include <linux/kthread.h>
 #include <linux/posix_acl.h>
@@ -210,240 +210,195 @@ enum {
        Opt_discard, Opt_nodiscard, Opt_discard_minblk
 };
 
-static const match_table_t tokens = {
-       {Opt_integrity, "integrity"},
-       {Opt_nointegrity, "nointegrity"},
-       {Opt_iocharset, "iocharset=%s"},
-       {Opt_resize, "resize=%u"},
-       {Opt_resize_nosize, "resize"},
-       {Opt_errors, "errors=%s"},
-       {Opt_ignore, "noquota"},
-       {Opt_quota, "quota"},
-       {Opt_usrquota, "usrquota"},
-       {Opt_grpquota, "grpquota"},
-       {Opt_uid, "uid=%u"},
-       {Opt_gid, "gid=%u"},
-       {Opt_umask, "umask=%u"},
-       {Opt_discard, "discard"},
-       {Opt_nodiscard, "nodiscard"},
-       {Opt_discard_minblk, "discard=%u"},
-       {Opt_err, NULL}
+static const struct constant_table jfs_param_errors[] = {
+       {"continue",    JFS_ERR_CONTINUE},
+       {"remount-ro",  JFS_ERR_REMOUNT_RO},
+       {"panic",       JFS_ERR_PANIC},
+       {}
 };
 
-static int parse_options(char *options, struct super_block *sb, s64 *newLVSize,
-                        int *flag)
-{
-       void *nls_map = (void *)-1;     /* -1: no change;  NULL: none */
-       char *p;
-       struct jfs_sb_info *sbi = JFS_SBI(sb);
+static const struct fs_parameter_spec jfs_param_spec[] = {
+       fsparam_flag_no ("integrity",   Opt_integrity),
+       fsparam_string  ("iocharset",   Opt_iocharset),
+       fsparam_u64     ("resize",      Opt_resize),
+       fsparam_flag    ("resize",      Opt_resize_nosize),
+       fsparam_enum    ("errors",      Opt_errors,     jfs_param_errors),
+       fsparam_flag    ("quota",       Opt_quota),
+       fsparam_flag    ("noquota",     Opt_ignore),
+       fsparam_flag    ("usrquota",    Opt_usrquota),
+       fsparam_flag    ("grpquota",    Opt_grpquota),
+       fsparam_uid     ("uid",         Opt_uid),
+       fsparam_gid     ("gid",         Opt_gid),
+       fsparam_u32oct  ("umask",       Opt_umask),
+       fsparam_flag    ("discard",     Opt_discard),
+       fsparam_u32     ("discard",     Opt_discard_minblk),
+       fsparam_flag    ("nodiscard",   Opt_nodiscard),
+       {}
+};
 
-       *newLVSize = 0;
-
-       if (!options)
-               return 1;
-
-       while ((p = strsep(&options, ",")) != NULL) {
-               substring_t args[MAX_OPT_ARGS];
-               int token;
-               if (!*p)
-                       continue;
-
-               token = match_token(p, tokens, args);
-               switch (token) {
-               case Opt_integrity:
-                       *flag &= ~JFS_NOINTEGRITY;
-                       break;
-               case Opt_nointegrity:
-                       *flag |= JFS_NOINTEGRITY;
-                       break;
-               case Opt_ignore:
-                       /* Silently ignore the quota options */
-                       /* Don't do anything ;-) */
-                       break;
-               case Opt_iocharset:
-                       if (nls_map && nls_map != (void *) -1)
-                               unload_nls(nls_map);
-                       if (!strcmp(args[0].from, "none"))
-                               nls_map = NULL;
-                       else {
-                               nls_map = load_nls(args[0].from);
-                               if (!nls_map) {
-                                       pr_err("JFS: charset not found\n");
-                                       goto cleanup;
-                               }
-                       }
-                       break;
-               case Opt_resize:
-               {
-                       char *resize = args[0].from;
-                       int rc = kstrtoll(resize, 0, newLVSize);
+struct jfs_context {
+       int     flag;
+       kuid_t  uid;
+       kgid_t  gid;
+       uint    umask;
+       uint    minblks_trim;
+       void    *nls_map;
+       bool    resize;
+       s64     newLVSize;
+};
 
-                       if (rc)
-                               goto cleanup;
-                       break;
-               }
-               case Opt_resize_nosize:
-               {
-                       *newLVSize = sb_bdev_nr_blocks(sb);
-                       if (*newLVSize == 0)
-                               pr_err("JFS: Cannot determine volume size\n");
-                       break;
+static int jfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
+{
+       struct jfs_context *ctx = fc->fs_private;
+       int reconfigure = (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE);
+       struct fs_parse_result result;
+       struct nls_table *nls_map;
+       int opt;
+
+       opt = fs_parse(fc, jfs_param_spec, param, &result);
+       if (opt < 0)
+               return opt;
+
+       switch (opt) {
+       case Opt_integrity:
+               if (result.negated)
+                       ctx->flag |= JFS_NOINTEGRITY;
+               else
+                       ctx->flag &= ~JFS_NOINTEGRITY;
+               break;
+       case Opt_ignore:
+               /* Silently ignore the quota options */
+               /* Don't do anything ;-) */
+               break;
+       case Opt_iocharset:
+               if (ctx->nls_map && ctx->nls_map != (void *) -1) {
+                       unload_nls(ctx->nls_map);
+                       ctx->nls_map = NULL;
                }
-               case Opt_errors:
-               {
-                       char *errors = args[0].from;
-                       if (!errors || !*errors)
-                               goto cleanup;
-                       if (!strcmp(errors, "continue")) {
-                               *flag &= ~JFS_ERR_REMOUNT_RO;
-                               *flag &= ~JFS_ERR_PANIC;
-                               *flag |= JFS_ERR_CONTINUE;
-                       } else if (!strcmp(errors, "remount-ro")) {
-                               *flag &= ~JFS_ERR_CONTINUE;
-                               *flag &= ~JFS_ERR_PANIC;
-                               *flag |= JFS_ERR_REMOUNT_RO;
-                       } else if (!strcmp(errors, "panic")) {
-                               *flag &= ~JFS_ERR_CONTINUE;
-                               *flag &= ~JFS_ERR_REMOUNT_RO;
-                               *flag |= JFS_ERR_PANIC;
-                       } else {
-                               pr_err("JFS: %s is an invalid error handler\n",
-                                      errors);
-                               goto cleanup;
+               if (!strcmp(param->string, "none"))
+                       ctx->nls_map = NULL;
+               else {
+                       nls_map = load_nls(param->string);
+                       if (!nls_map) {
+                               pr_err("JFS: charset not found\n");
+                               return -EINVAL;
                        }
-                       break;
+                       ctx->nls_map = nls_map;
                }
+               break;
+       case Opt_resize:
+               if (!reconfigure)
+                       return -EINVAL;
+               ctx->resize = true;
+               ctx->newLVSize = result.uint_64;
+               break;
+       case Opt_resize_nosize:
+               if (!reconfigure)
+                       return -EINVAL;
+               ctx->resize = true;
+               break;
+       case Opt_errors:
+               ctx->flag &= ~JFS_ERR_MASK;
+               ctx->flag |= result.uint_32;
+               break;
 
 #ifdef CONFIG_QUOTA
-               case Opt_quota:
-               case Opt_usrquota:
-                       *flag |= JFS_USRQUOTA;
-                       break;
-               case Opt_grpquota:
-                       *flag |= JFS_GRPQUOTA;
-                       break;
+       case Opt_quota:
+       case Opt_usrquota:
+               ctx->flag |= JFS_USRQUOTA;
+               break;
+       case Opt_grpquota:
+               ctx->flag |= JFS_GRPQUOTA;
+               break;
 #else
-               case Opt_usrquota:
-               case Opt_grpquota:
-               case Opt_quota:
-                       pr_err("JFS: quota operations not supported\n");
-                       break;
+       case Opt_usrquota:
+       case Opt_grpquota:
+       case Opt_quota:
+               pr_err("JFS: quota operations not supported\n");
+               break;
 #endif
-               case Opt_uid:
-               {
-                       char *uid = args[0].from;
-                       uid_t val;
-                       int rc = kstrtouint(uid, 0, &val);
-
-                       if (rc)
-                               goto cleanup;
-                       sbi->uid = make_kuid(current_user_ns(), val);
-                       if (!uid_valid(sbi->uid))
-                               goto cleanup;
-                       break;
-               }
-
-               case Opt_gid:
-               {
-                       char *gid = args[0].from;
-                       gid_t val;
-                       int rc = kstrtouint(gid, 0, &val);
-
-                       if (rc)
-                               goto cleanup;
-                       sbi->gid = make_kgid(current_user_ns(), val);
-                       if (!gid_valid(sbi->gid))
-                               goto cleanup;
-                       break;
+       case Opt_uid:
+               ctx->uid = result.uid;
+               break;
+
+       case Opt_gid:
+               ctx->gid = result.gid;
+               break;
+
+       case Opt_umask:
+               if (result.uint_32 & ~0777) {
+                       pr_err("JFS: Invalid value of umask\n");
+                       return -EINVAL;
                }
+               ctx->umask = result.uint_32;
+               break;
 
-               case Opt_umask:
-               {
-                       char *umask = args[0].from;
-                       int rc = kstrtouint(umask, 8, &sbi->umask);
+       case Opt_discard:
+               /* if set to 1, even copying files will cause
+                * trimming :O
+                * -> user has more control over the online trimming
+                */
+               ctx->minblks_trim = 64;
+               ctx->flag |= JFS_DISCARD;
+               break;
 
-                       if (rc)
-                               goto cleanup;
-                       if (sbi->umask & ~0777) {
-                               pr_err("JFS: Invalid value of umask\n");
-                               goto cleanup;
-                       }
-                       break;
-               }
+       case Opt_nodiscard:
+               ctx->flag &= ~JFS_DISCARD;
+               break;
 
-               case Opt_discard:
-                       /* if set to 1, even copying files will cause
-                        * trimming :O
-                        * -> user has more control over the online trimming
-                        */
-                       sbi->minblks_trim = 64;
-                       if (bdev_max_discard_sectors(sb->s_bdev))
-                               *flag |= JFS_DISCARD;
-                       else
-                               pr_err("JFS: discard option not supported on device\n");
-                       break;
-
-               case Opt_nodiscard:
-                       *flag &= ~JFS_DISCARD;
-                       break;
-
-               case Opt_discard_minblk:
-               {
-                       char *minblks_trim = args[0].from;
-                       int rc;
-                       if (bdev_max_discard_sectors(sb->s_bdev)) {
-                               *flag |= JFS_DISCARD;
-                               rc = kstrtouint(minblks_trim, 0,
-                                               &sbi->minblks_trim);
-                               if (rc)
-                                       goto cleanup;
-                       } else
-                               pr_err("JFS: discard option not supported on device\n");
-                       break;
-               }
+       case Opt_discard_minblk:
+               ctx->minblks_trim = result.uint_32;
+               ctx->flag |= JFS_DISCARD;
+               break;
 
-               default:
-                       printk("jfs: Unrecognized mount option \"%s\" or missing value\n",
-                              p);
-                       goto cleanup;
-               }
-       }
-
-       if (nls_map != (void *) -1) {
-               /* Discard old (if remount) */
-               unload_nls(sbi->nls_tab);
-               sbi->nls_tab = nls_map;
+       default:
+               return -EINVAL;
        }
-       return 1;
 
-cleanup:
-       if (nls_map && nls_map != (void *) -1)
-               unload_nls(nls_map);
        return 0;
 }
 
-static int jfs_remount(struct super_block *sb, int *flags, char *data)
+static int jfs_reconfigure(struct fs_context *fc)
 {
-       s64 newLVSize = 0;
+       struct jfs_context *ctx = fc->fs_private;
+       struct super_block *sb = fc->root->d_sb;
+       int readonly = fc->sb_flags & SB_RDONLY;
        int rc = 0;
-       int flag = JFS_SBI(sb)->flag;
+       int flag = ctx->flag;
        int ret;
 
        sync_filesystem(sb);
-       if (!parse_options(data, sb, &newLVSize, &flag))
-               return -EINVAL;
 
-       if (newLVSize) {
+       /* Transfer results of parsing to the sbi */
+       JFS_SBI(sb)->flag = ctx->flag;
+       JFS_SBI(sb)->uid = ctx->uid;
+       JFS_SBI(sb)->gid = ctx->gid;
+       JFS_SBI(sb)->umask = ctx->umask;
+       JFS_SBI(sb)->minblks_trim = ctx->minblks_trim;
+       if (ctx->nls_map != (void *) -1) {
+               unload_nls(JFS_SBI(sb)->nls_tab);
+               JFS_SBI(sb)->nls_tab = ctx->nls_map;
+       }
+       ctx->nls_map = NULL;
+
+       if (ctx->resize) {
                if (sb_rdonly(sb)) {
                        pr_err("JFS: resize requires volume to be mounted read-write\n");
                        return -EROFS;
                }
-               rc = jfs_extendfs(sb, newLVSize, 0);
+
+               if (!ctx->newLVSize) {
+                       ctx->newLVSize = sb_bdev_nr_blocks(sb);
+                               if (ctx->newLVSize == 0)
+                                       pr_err("JFS: Cannot determine volume size\n");
+               }
+
+               rc = jfs_extendfs(sb, ctx->newLVSize, 0);
                if (rc)
                        return rc;
        }
 
-       if (sb_rdonly(sb) && !(*flags & SB_RDONLY)) {
+       if (sb_rdonly(sb) && !readonly) {
                /*
                 * Invalidate any previously read metadata.  fsck may have
                 * changed the on-disk data since we mounted r/o
@@ -459,7 +414,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
                dquot_resume(sb, -1);
                return ret;
        }
-       if (!sb_rdonly(sb) && (*flags & SB_RDONLY)) {
+       if (!sb_rdonly(sb) && readonly) {
                rc = dquot_suspend(sb, -1);
                if (rc < 0)
                        return rc;
@@ -467,7 +422,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
                JFS_SBI(sb)->flag = flag;
                return rc;
        }
-       if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY))
+       if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY)) {
                if (!sb_rdonly(sb)) {
                        rc = jfs_umount_rw(sb);
                        if (rc)
@@ -477,18 +432,20 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
                        ret = jfs_mount_rw(sb, 1);
                        return ret;
                }
+       }
        JFS_SBI(sb)->flag = flag;
 
        return 0;
 }
 
-static int jfs_fill_super(struct super_block *sb, void *data, int silent)
+static int jfs_fill_super(struct super_block *sb, struct fs_context *fc)
 {
+       struct jfs_context *ctx = fc->fs_private;
+       int silent = fc->sb_flags & SB_SILENT;
        struct jfs_sb_info *sbi;
        struct inode *inode;
        int rc;
-       s64 newLVSize = 0;
-       int flag, ret = -EINVAL;
+       int ret = -EINVAL;
 
        jfs_info("In jfs_read_super: s_flags=0x%lx", sb->s_flags);
 
@@ -501,24 +458,34 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
        sb->s_time_min = 0;
        sb->s_time_max = U32_MAX;
        sbi->sb = sb;
-       sbi->uid = INVALID_UID;
-       sbi->gid = INVALID_GID;
-       sbi->umask = -1;
-
-       /* initialize the mount flag and determine the default error handler */
-       flag = JFS_ERR_REMOUNT_RO;
 
-       if (!parse_options((char *) data, sb, &newLVSize, &flag))
-               goto out_kfree;
-       sbi->flag = flag;
+       /* Transfer results of parsing to the sbi */
+       sbi->flag = ctx->flag;
+       sbi->uid = ctx->uid;
+       sbi->gid = ctx->gid;
+       sbi->umask = ctx->umask;
+       if (ctx->nls_map != (void *) -1) {
+               unload_nls(sbi->nls_tab);
+               sbi->nls_tab = ctx->nls_map;
+       }
+       ctx->nls_map = NULL;
+
+       if (sbi->flag & JFS_DISCARD) {
+               if (!bdev_max_discard_sectors(sb->s_bdev)) {
+                       pr_err("JFS: discard option not supported on device\n");
+                       sbi->flag &= ~JFS_DISCARD;
+               } else {
+                       sbi->minblks_trim = ctx->minblks_trim;
+               }
+       }
 
 #ifdef CONFIG_JFS_POSIX_ACL
        sb->s_flags |= SB_POSIXACL;
 #endif
 
-       if (newLVSize) {
+       if (ctx->resize) {
                pr_err("resize option for remount only\n");
-               goto out_kfree;
+               goto out_unload;
        }
 
        /*
@@ -608,7 +575,6 @@ out_mount_failed:
        sbi->direct_inode = NULL;
 out_unload:
        unload_nls(sbi->nls_tab);
-out_kfree:
        kfree(sbi);
        return ret;
 }
@@ -664,10 +630,9 @@ out:
        return rc;
 }
 
-static struct dentry *jfs_do_mount(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int jfs_get_tree(struct fs_context *fc)
 {
-       return mount_bdev(fs_type, flags, dev_name, data, jfs_fill_super);
+       return get_tree_bdev(fc, jfs_fill_super);
 }
 
 static int jfs_sync_fs(struct super_block *sb, int wait)
@@ -886,7 +851,6 @@ static const struct super_operations jfs_super_operations = {
        .freeze_fs      = jfs_freeze,
        .unfreeze_fs    = jfs_unfreeze,
        .statfs         = jfs_statfs,
-       .remount_fs     = jfs_remount,
        .show_options   = jfs_show_options,
 #ifdef CONFIG_QUOTA
        .quota_read     = jfs_quota_read,
@@ -902,12 +866,71 @@ static const struct export_operations jfs_export_operations = {
        .get_parent     = jfs_get_parent,
 };
 
+static void jfs_init_options(struct fs_context *fc, struct jfs_context *ctx)
+{
+       if (fc->purpose == FS_CONTEXT_FOR_RECONFIGURE) {
+               struct super_block *sb = fc->root->d_sb;
+
+               /* Copy over current option values and mount flags */
+               ctx->uid = JFS_SBI(sb)->uid;
+               ctx->gid = JFS_SBI(sb)->gid;
+               ctx->umask = JFS_SBI(sb)->umask;
+               ctx->nls_map = (void *)-1;
+               ctx->minblks_trim = JFS_SBI(sb)->minblks_trim;
+               ctx->flag = JFS_SBI(sb)->flag;
+
+       } else {
+               /*
+                * Initialize the mount flag and determine the default
+                * error handler
+                */
+               ctx->flag = JFS_ERR_REMOUNT_RO;
+               ctx->uid = INVALID_UID;
+               ctx->gid = INVALID_GID;
+               ctx->umask = -1;
+               ctx->nls_map = (void *)-1;
+       }
+}
+
+static void jfs_free_fc(struct fs_context *fc)
+{
+       struct jfs_context *ctx = fc->fs_private;
+
+       if (ctx->nls_map != (void *) -1)
+               unload_nls(ctx->nls_map);
+       kfree(ctx);
+}
+
+static const struct fs_context_operations jfs_context_ops = {
+       .parse_param    = jfs_parse_param,
+       .get_tree       = jfs_get_tree,
+       .reconfigure    = jfs_reconfigure,
+       .free           = jfs_free_fc,
+};
+
+static int jfs_init_fs_context(struct fs_context *fc)
+{
+       struct jfs_context *ctx;
+
+       ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       jfs_init_options(fc, ctx);
+
+       fc->fs_private = ctx;
+       fc->ops = &jfs_context_ops;
+
+       return 0;
+}
+
 static struct file_system_type jfs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "jfs",
-       .mount          = jfs_do_mount,
        .kill_sb        = kill_block_super,
        .fs_flags       = FS_REQUIRES_DEV,
+       .init_fs_context = jfs_init_fs_context,
+       .parameters     = jfs_param_spec,
 };
 MODULE_ALIAS_FS("jfs");