summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2018-12-24 00:55:56 +0100
committerAl Viro <viro@zeniv.linux.org.uk>2019-01-30 23:44:27 +0100
commitf3a09c92018a91ad0981146a4ac59414f814d801 (patch)
treec500afabc514faf977ceacfbe57ce04910bcc3e0 /fs
parentfs_context flavour for submounts (diff)
downloadlinux-f3a09c92018a91ad0981146a4ac59414f814d801.tar.xz
linux-f3a09c92018a91ad0981146a4ac59414f814d801.zip
introduce fs_context methods
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/fs_context.c28
-rw-r--r--fs/internal.h2
-rw-r--r--fs/super.c36
3 files changed, 50 insertions, 16 deletions
diff --git a/fs/fs_context.c b/fs/fs_context.c
index 2bd652b6e848..825d1b2c8807 100644
--- a/fs/fs_context.c
+++ b/fs/fs_context.c
@@ -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);
}
diff --git a/fs/internal.h b/fs/internal.h
index 016a5b8dd305..8f8d07cc433f 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -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 *);
diff --git a/fs/super.c b/fs/super.c
index 50553233dd15..76b3181c782d 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -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);