introduce fs_context methods
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 23 Dec 2018 23:55:56 +0000 (18:55 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 30 Jan 2019 22:44:27 +0000 (17:44 -0500)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/fs_context.c
fs/internal.h
fs/super.c
include/linux/fs.h
include/linux/fs_context.h

index 2bd652b..825d1b2 100644 (file)
@@ -51,6 +51,7 @@ static struct fs_context *alloc_fs_context(struct file_system_type *fs_type,
                                      unsigned int sb_flags_mask,
                                      enum fs_context_purpose purpose)
 {
+       int (*init_fs_context)(struct fs_context *);
        struct fs_context *fc;
        int ret = -ENOMEM;
 
@@ -81,7 +82,12 @@ static struct fs_context *alloc_fs_context(struct file_system_type *fs_type,
                break;
        }
 
-       ret = legacy_init_fs_context(fc);
+       /* TODO: Make all filesystems support this unconditionally */
+       init_fs_context = fc->fs_type->init_fs_context;
+       if (!init_fs_context)
+               init_fs_context = legacy_init_fs_context;
+
+       ret = init_fs_context(fc);
        if (ret < 0)
                goto err_fc;
        fc->need_free = true;
@@ -141,8 +147,8 @@ void put_fs_context(struct fs_context *fc)
                deactivate_super(sb);
        }
 
-       if (fc->need_free)
-               legacy_fs_context_free(fc);
+       if (fc->need_free && fc->ops && fc->ops->free)
+               fc->ops->free(fc);
 
        security_free_mnt_opts(&fc->security);
        put_net(fc->net_ns);
@@ -180,7 +186,7 @@ static int legacy_parse_monolithic(struct fs_context *fc, void *data)
 /*
  * Get a mountable root with the legacy mount command.
  */
-int legacy_get_tree(struct fs_context *fc)
+static int legacy_get_tree(struct fs_context *fc)
 {
        struct legacy_fs_context *ctx = fc->fs_private;
        struct super_block *sb;
@@ -201,7 +207,7 @@ int legacy_get_tree(struct fs_context *fc)
 /*
  * Handle remount.
  */
-int legacy_reconfigure(struct fs_context *fc)
+static int legacy_reconfigure(struct fs_context *fc)
 {
        struct legacy_fs_context *ctx = fc->fs_private;
        struct super_block *sb = fc->root->d_sb;
@@ -213,6 +219,13 @@ int legacy_reconfigure(struct fs_context *fc)
                                    ctx ? ctx->legacy_data : NULL);
 }
 
+const struct fs_context_operations legacy_fs_context_ops = {
+       .free                   = legacy_fs_context_free,
+       .parse_monolithic       = legacy_parse_monolithic,
+       .get_tree               = legacy_get_tree,
+       .reconfigure            = legacy_reconfigure,
+};
+
 /*
  * Initialise a legacy context for a filesystem that doesn't support
  * fs_context.
@@ -222,10 +235,13 @@ static int legacy_init_fs_context(struct fs_context *fc)
        fc->fs_private = kzalloc(sizeof(struct legacy_fs_context), GFP_KERNEL);
        if (!fc->fs_private)
                return -ENOMEM;
+       fc->ops = &legacy_fs_context_ops;
        return 0;
 }
 
 int parse_monolithic_mount_data(struct fs_context *fc, void *data)
 {
-       return legacy_parse_monolithic(fc, data);
+       int (*monolithic_mount_data)(struct fs_context *, void *);
+       monolithic_mount_data = fc->ops->parse_monolithic;
+       return monolithic_mount_data(fc, data);
 }
index 016a5b8..8f8d07c 100644 (file)
@@ -55,8 +55,6 @@ extern void __init chrdev_init(void);
 /*
  * fs_context.c
  */
-extern int legacy_get_tree(struct fs_context *fc);
-extern int legacy_reconfigure(struct fs_context *fc);
 extern int parse_monolithic_mount_data(struct fs_context *, void *);
 extern void fc_drop_locked(struct fs_context *);
 
index 5055323..76b3181 100644 (file)
@@ -894,13 +894,15 @@ int reconfigure_super(struct fs_context *fc)
                }
        }
 
-       retval = legacy_reconfigure(fc);
-       if (retval) {
-               if (!force)
-                       goto cancel_readonly;
-               /* If forced remount, go ahead despite any errors */
-               WARN(1, "forced remount of a %s fs returned %i\n",
-                    sb->s_type->name, retval);
+       if (fc->ops->reconfigure) {
+               retval = fc->ops->reconfigure(fc);
+               if (retval) {
+                       if (!force)
+                               goto cancel_readonly;
+                       /* If forced remount, go ahead despite any errors */
+                       WARN(1, "forced remount of a %s fs returned %i\n",
+                            sb->s_type->name, retval);
+               }
        }
 
        WRITE_ONCE(sb->s_flags, ((sb->s_flags & ~fc->sb_flags_mask) |
@@ -1294,10 +1296,28 @@ int vfs_get_tree(struct fs_context *fc)
        struct super_block *sb;
        int error;
 
-       error = legacy_get_tree(fc);
+       if (fc->fs_type->fs_flags & FS_REQUIRES_DEV && !fc->source)
+               return -ENOENT;
+
+       if (fc->root)
+               return -EBUSY;
+
+       /* Get the mountable root in fc->root, with a ref on the root and a ref
+        * on the superblock.
+        */
+       error = fc->ops->get_tree(fc);
        if (error < 0)
                return error;
 
+       if (!fc->root) {
+               pr_err("Filesystem %s get_tree() didn't set fc->root\n",
+                      fc->fs_type->name);
+               /* We don't know what the locking state of the superblock is -
+                * if there is a superblock.
+                */
+               BUG();
+       }
+
        sb = fc->root->d_sb;
        WARN_ON(!sb->s_bdi);
 
index c65d02c..8d578a9 100644 (file)
@@ -61,6 +61,7 @@ struct workqueue_struct;
 struct iov_iter;
 struct fscrypt_info;
 struct fscrypt_operations;
+struct fs_context;
 
 extern void __init inode_init(void);
 extern void __init inode_init_early(void);
@@ -2173,6 +2174,7 @@ struct file_system_type {
 #define FS_HAS_SUBTYPE         4
 #define FS_USERNS_MOUNT                8       /* Can be mounted by userns root */
 #define FS_RENAME_DOES_D_MOVE  32768   /* FS will handle d_move() during rename() internally. */
+       int (*init_fs_context)(struct fs_context *);
        struct dentry *(*mount) (struct file_system_type *, int,
                       const char *, void *);
        void (*kill_sb) (struct super_block *);
index 7feb018..087c129 100644 (file)
@@ -20,8 +20,13 @@ struct cred;
 struct dentry;
 struct file_operations;
 struct file_system_type;
+struct mnt_namespace;
 struct net;
+struct pid_namespace;
+struct super_block;
 struct user_namespace;
+struct vfsmount;
+struct path;
 
 enum fs_context_purpose {
        FS_CONTEXT_FOR_MOUNT,           /* New superblock for explicit mount */
@@ -39,6 +44,7 @@ enum fs_context_purpose {
  * See Documentation/filesystems/mounting.txt
  */
 struct fs_context {
+       const struct fs_context_operations *ops;
        struct file_system_type *fs_type;
        void                    *fs_private;    /* The filesystem's context */
        struct dentry           *root;          /* The root and superblock */
@@ -54,6 +60,13 @@ struct fs_context {
        bool                    need_free:1;    /* Need to call ops->free() */
 };
 
+struct fs_context_operations {
+       void (*free)(struct fs_context *fc);
+       int (*parse_monolithic)(struct fs_context *fc, void *data);
+       int (*get_tree)(struct fs_context *fc);
+       int (*reconfigure)(struct fs_context *fc);
+};
+
 /*
  * fs_context manipulation functions.
  */