mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-30 22:50:54 -04:00
Merge patch series "fs: last of the pseudofs mount api conversions"
Eric Sandeen <sandeen@redhat.com> says: pstore used mount_single, which used to transparently do a remount operation on a fresh mount of an existing superblock. The new get_tree_single does not do this, but prior discussion on fsdevel seems to indicate that this isn't expected to be a problem. We can watch for issues. devpts is just a forward port from work dhowells did already, and it seems straightforward. I left error messages as they are rather than converting to the mount API message channel for now. devtmpfs was already converted, but left a .mount in place, rather than using .get_tree. The solution to this is ... unique so some scrutiny is probably wise. The last patch removes reconfigure_single, mount_single, and compare_single because no users remain, but we could also wait until all conversions are done, and remove all infrastructure at that time instead, if desired. * patches from https://lore.kernel.org/r/20250205213931.74614-1-sandeen@redhat.com: vfs: remove some unused old mount api code devtmpfs: replace ->mount with ->get_tree in public instance vfs: Convert devpts to use the new mount API pstore: convert to the new mount API Link: https://lore.kernel.org/r/20250205213931.74614-1-sandeen@redhat.com Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
@@ -63,22 +63,6 @@ __setup("devtmpfs.mount=", mount_param);
|
||||
|
||||
static struct vfsmount *mnt;
|
||||
|
||||
static struct dentry *public_dev_mount(struct file_system_type *fs_type, int flags,
|
||||
const char *dev_name, void *data)
|
||||
{
|
||||
struct super_block *s = mnt->mnt_sb;
|
||||
int err;
|
||||
|
||||
atomic_inc(&s->s_active);
|
||||
down_write(&s->s_umount);
|
||||
err = reconfigure_single(s, flags, data);
|
||||
if (err < 0) {
|
||||
deactivate_locked_super(s);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
return dget(s->s_root);
|
||||
}
|
||||
|
||||
static struct file_system_type internal_fs_type = {
|
||||
.name = "devtmpfs",
|
||||
#ifdef CONFIG_TMPFS
|
||||
@@ -89,9 +73,40 @@ static struct file_system_type internal_fs_type = {
|
||||
.kill_sb = kill_litter_super,
|
||||
};
|
||||
|
||||
/* Simply take a ref on the existing mount */
|
||||
static int devtmpfs_get_tree(struct fs_context *fc)
|
||||
{
|
||||
struct super_block *sb = mnt->mnt_sb;
|
||||
|
||||
atomic_inc(&sb->s_active);
|
||||
down_write(&sb->s_umount);
|
||||
fc->root = dget(sb->s_root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Ops are filled in during init depending on underlying shmem or ramfs type */
|
||||
struct fs_context_operations devtmpfs_context_ops = {};
|
||||
|
||||
/* Call the underlying initialization and set to our ops */
|
||||
static int devtmpfs_init_fs_context(struct fs_context *fc)
|
||||
{
|
||||
int ret;
|
||||
#ifdef CONFIG_TMPFS
|
||||
ret = shmem_init_fs_context(fc);
|
||||
#else
|
||||
ret = ramfs_init_fs_context(fc);
|
||||
#endif
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fc->ops = &devtmpfs_context_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_system_type dev_fs_type = {
|
||||
.name = "devtmpfs",
|
||||
.mount = public_dev_mount,
|
||||
.init_fs_context = devtmpfs_init_fs_context,
|
||||
};
|
||||
|
||||
static int devtmpfs_submit_req(struct req *req, const char *tmp)
|
||||
@@ -442,6 +457,31 @@ static int __ref devtmpfsd(void *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the underlying (shmem/ramfs) context ops to build ours
|
||||
*/
|
||||
static int devtmpfs_configure_context(void)
|
||||
{
|
||||
struct fs_context *fc;
|
||||
|
||||
fc = fs_context_for_reconfigure(mnt->mnt_root, mnt->mnt_sb->s_flags,
|
||||
MS_RMT_MASK);
|
||||
if (IS_ERR(fc))
|
||||
return PTR_ERR(fc);
|
||||
|
||||
/* Set up devtmpfs_context_ops based on underlying type */
|
||||
devtmpfs_context_ops.free = fc->ops->free;
|
||||
devtmpfs_context_ops.dup = fc->ops->dup;
|
||||
devtmpfs_context_ops.parse_param = fc->ops->parse_param;
|
||||
devtmpfs_context_ops.parse_monolithic = fc->ops->parse_monolithic;
|
||||
devtmpfs_context_ops.get_tree = &devtmpfs_get_tree;
|
||||
devtmpfs_context_ops.reconfigure = fc->ops->reconfigure;
|
||||
|
||||
put_fs_context(fc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create devtmpfs instance, driver-core devices will add their device
|
||||
* nodes here.
|
||||
@@ -456,6 +496,13 @@ int __init devtmpfs_init(void)
|
||||
pr_err("unable to create devtmpfs %ld\n", PTR_ERR(mnt));
|
||||
return PTR_ERR(mnt);
|
||||
}
|
||||
|
||||
err = devtmpfs_configure_context();
|
||||
if (err) {
|
||||
pr_err("unable to configure devtmpfs type %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = register_filesystem(&dev_fs_type);
|
||||
if (err) {
|
||||
pr_err("unable to register devtmpfs type %d\n", err);
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/fs_context.h>
|
||||
#include <linux/fs_parser.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -21,7 +23,6 @@
|
||||
#include <linux/magic.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/devpts_fs.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
@@ -87,14 +88,14 @@ enum {
|
||||
Opt_err
|
||||
};
|
||||
|
||||
static const match_table_t tokens = {
|
||||
{Opt_uid, "uid=%u"},
|
||||
{Opt_gid, "gid=%u"},
|
||||
{Opt_mode, "mode=%o"},
|
||||
{Opt_ptmxmode, "ptmxmode=%o"},
|
||||
{Opt_newinstance, "newinstance"},
|
||||
{Opt_max, "max=%d"},
|
||||
{Opt_err, NULL}
|
||||
static const struct fs_parameter_spec devpts_param_specs[] = {
|
||||
fsparam_u32 ("gid", Opt_gid),
|
||||
fsparam_s32 ("max", Opt_max),
|
||||
fsparam_u32oct ("mode", Opt_mode),
|
||||
fsparam_flag ("newinstance", Opt_newinstance),
|
||||
fsparam_u32oct ("ptmxmode", Opt_ptmxmode),
|
||||
fsparam_u32 ("uid", Opt_uid),
|
||||
{}
|
||||
};
|
||||
|
||||
struct pts_fs_info {
|
||||
@@ -214,93 +215,48 @@ void devpts_release(struct pts_fs_info *fsi)
|
||||
deactivate_super(fsi->sb);
|
||||
}
|
||||
|
||||
#define PARSE_MOUNT 0
|
||||
#define PARSE_REMOUNT 1
|
||||
|
||||
/*
|
||||
* parse_mount_options():
|
||||
* Set @opts to mount options specified in @data. If an option is not
|
||||
* specified in @data, set it to its default value.
|
||||
*
|
||||
* Note: @data may be NULL (in which case all options are set to default).
|
||||
* devpts_parse_param - Parse mount parameters
|
||||
*/
|
||||
static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts)
|
||||
static int devpts_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
{
|
||||
char *p;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
struct pts_fs_info *fsi = fc->s_fs_info;
|
||||
struct pts_mount_opts *opts = &fsi->mount_opts;
|
||||
struct fs_parse_result result;
|
||||
int opt;
|
||||
|
||||
opts->setuid = 0;
|
||||
opts->setgid = 0;
|
||||
opts->uid = GLOBAL_ROOT_UID;
|
||||
opts->gid = GLOBAL_ROOT_GID;
|
||||
opts->mode = DEVPTS_DEFAULT_MODE;
|
||||
opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
|
||||
opts->max = NR_UNIX98_PTY_MAX;
|
||||
opt = fs_parse(fc, devpts_param_specs, param, &result);
|
||||
if (opt < 0)
|
||||
return opt;
|
||||
|
||||
/* Only allow instances mounted from the initial mount
|
||||
* namespace to tap the reserve pool of ptys.
|
||||
*/
|
||||
if (op == PARSE_MOUNT)
|
||||
opts->reserve =
|
||||
(current->nsproxy->mnt_ns == init_task.nsproxy->mnt_ns);
|
||||
|
||||
while ((p = strsep(&data, ",")) != NULL) {
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
int token;
|
||||
int option;
|
||||
|
||||
if (!*p)
|
||||
continue;
|
||||
|
||||
token = match_token(p, tokens, args);
|
||||
switch (token) {
|
||||
case Opt_uid:
|
||||
if (match_int(&args[0], &option))
|
||||
return -EINVAL;
|
||||
uid = make_kuid(current_user_ns(), option);
|
||||
if (!uid_valid(uid))
|
||||
return -EINVAL;
|
||||
opts->uid = uid;
|
||||
opts->setuid = 1;
|
||||
break;
|
||||
case Opt_gid:
|
||||
if (match_int(&args[0], &option))
|
||||
return -EINVAL;
|
||||
gid = make_kgid(current_user_ns(), option);
|
||||
if (!gid_valid(gid))
|
||||
return -EINVAL;
|
||||
opts->gid = gid;
|
||||
opts->setgid = 1;
|
||||
break;
|
||||
case Opt_mode:
|
||||
if (match_octal(&args[0], &option))
|
||||
return -EINVAL;
|
||||
opts->mode = option & S_IALLUGO;
|
||||
break;
|
||||
case Opt_ptmxmode:
|
||||
if (match_octal(&args[0], &option))
|
||||
return -EINVAL;
|
||||
opts->ptmxmode = option & S_IALLUGO;
|
||||
break;
|
||||
case Opt_newinstance:
|
||||
break;
|
||||
case Opt_max:
|
||||
if (match_int(&args[0], &option) ||
|
||||
option < 0 || option > NR_UNIX98_PTY_MAX)
|
||||
return -EINVAL;
|
||||
opts->max = option;
|
||||
break;
|
||||
default:
|
||||
pr_err("called with bogus options\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (opt) {
|
||||
case Opt_uid:
|
||||
opts->uid = result.uid;
|
||||
opts->setuid = 1;
|
||||
break;
|
||||
case Opt_gid:
|
||||
opts->gid = result.gid;
|
||||
opts->setgid = 1;
|
||||
break;
|
||||
case Opt_mode:
|
||||
opts->mode = result.uint_32 & S_IALLUGO;
|
||||
break;
|
||||
case Opt_ptmxmode:
|
||||
opts->ptmxmode = result.uint_32 & S_IALLUGO;
|
||||
break;
|
||||
case Opt_newinstance:
|
||||
break;
|
||||
case Opt_max:
|
||||
if (result.uint_32 > NR_UNIX98_PTY_MAX)
|
||||
return invalf(fc, "max out of range");
|
||||
opts->max = result.uint_32;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mknod_ptmx(struct super_block *sb)
|
||||
static int mknod_ptmx(struct super_block *sb, struct fs_context *fc)
|
||||
{
|
||||
int mode;
|
||||
int rc = -ENOMEM;
|
||||
@@ -362,13 +318,23 @@ static void update_ptmx_mode(struct pts_fs_info *fsi)
|
||||
}
|
||||
}
|
||||
|
||||
static int devpts_remount(struct super_block *sb, int *flags, char *data)
|
||||
static int devpts_reconfigure(struct fs_context *fc)
|
||||
{
|
||||
int err;
|
||||
struct pts_fs_info *fsi = DEVPTS_SB(sb);
|
||||
struct pts_mount_opts *opts = &fsi->mount_opts;
|
||||
struct pts_fs_info *fsi = DEVPTS_SB(fc->root->d_sb);
|
||||
struct pts_fs_info *new = fc->s_fs_info;
|
||||
|
||||
err = parse_mount_options(data, PARSE_REMOUNT, opts);
|
||||
/* Apply the revised options. We don't want to change ->reserve.
|
||||
* Ideally, we'd update each option conditionally on it having been
|
||||
* explicitly changed, but the default is to reset everything so that
|
||||
* would break UAPI...
|
||||
*/
|
||||
fsi->mount_opts.setuid = new->mount_opts.setuid;
|
||||
fsi->mount_opts.setgid = new->mount_opts.setgid;
|
||||
fsi->mount_opts.uid = new->mount_opts.uid;
|
||||
fsi->mount_opts.gid = new->mount_opts.gid;
|
||||
fsi->mount_opts.mode = new->mount_opts.mode;
|
||||
fsi->mount_opts.ptmxmode = new->mount_opts.ptmxmode;
|
||||
fsi->mount_opts.max = new->mount_opts.max;
|
||||
|
||||
/*
|
||||
* parse_mount_options() restores options to default values
|
||||
@@ -378,7 +344,7 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
|
||||
*/
|
||||
update_ptmx_mode(fsi);
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int devpts_show_options(struct seq_file *seq, struct dentry *root)
|
||||
@@ -402,31 +368,13 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root)
|
||||
|
||||
static const struct super_operations devpts_sops = {
|
||||
.statfs = simple_statfs,
|
||||
.remount_fs = devpts_remount,
|
||||
.show_options = devpts_show_options,
|
||||
};
|
||||
|
||||
static void *new_pts_fs_info(struct super_block *sb)
|
||||
{
|
||||
struct pts_fs_info *fsi;
|
||||
|
||||
fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL);
|
||||
if (!fsi)
|
||||
return NULL;
|
||||
|
||||
ida_init(&fsi->allocated_ptys);
|
||||
fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
|
||||
fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
|
||||
fsi->sb = sb;
|
||||
|
||||
return fsi;
|
||||
}
|
||||
|
||||
static int
|
||||
devpts_fill_super(struct super_block *s, void *data, int silent)
|
||||
static int devpts_fill_super(struct super_block *s, struct fs_context *fc)
|
||||
{
|
||||
struct pts_fs_info *fsi = DEVPTS_SB(s);
|
||||
struct inode *inode;
|
||||
int error;
|
||||
|
||||
s->s_iflags &= ~SB_I_NODEV;
|
||||
s->s_blocksize = 1024;
|
||||
@@ -435,20 +383,11 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
|
||||
s->s_op = &devpts_sops;
|
||||
s->s_d_op = &simple_dentry_operations;
|
||||
s->s_time_gran = 1;
|
||||
fsi->sb = s;
|
||||
|
||||
error = -ENOMEM;
|
||||
s->s_fs_info = new_pts_fs_info(s);
|
||||
if (!s->s_fs_info)
|
||||
goto fail;
|
||||
|
||||
error = parse_mount_options(data, PARSE_MOUNT, &DEVPTS_SB(s)->mount_opts);
|
||||
if (error)
|
||||
goto fail;
|
||||
|
||||
error = -ENOMEM;
|
||||
inode = new_inode(s);
|
||||
if (!inode)
|
||||
goto fail;
|
||||
return -ENOMEM;
|
||||
inode->i_ino = 1;
|
||||
simple_inode_init_ts(inode);
|
||||
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
|
||||
@@ -459,31 +398,60 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
|
||||
s->s_root = d_make_root(inode);
|
||||
if (!s->s_root) {
|
||||
pr_err("get root dentry failed\n");
|
||||
goto fail;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
error = mknod_ptmx(s);
|
||||
if (error)
|
||||
goto fail_dput;
|
||||
|
||||
return 0;
|
||||
fail_dput:
|
||||
dput(s->s_root);
|
||||
s->s_root = NULL;
|
||||
fail:
|
||||
return error;
|
||||
return mknod_ptmx(s, fc);
|
||||
}
|
||||
|
||||
/*
|
||||
* devpts_mount()
|
||||
* devpts_get_tree()
|
||||
*
|
||||
* Mount a new (private) instance of devpts. PTYs created in this
|
||||
* instance are independent of the PTYs in other devpts instances.
|
||||
*/
|
||||
static struct dentry *devpts_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
static int devpts_get_tree(struct fs_context *fc)
|
||||
{
|
||||
return mount_nodev(fs_type, flags, data, devpts_fill_super);
|
||||
return get_tree_nodev(fc, devpts_fill_super);
|
||||
}
|
||||
|
||||
static void devpts_free_fc(struct fs_context *fc)
|
||||
{
|
||||
kfree(fc->s_fs_info);
|
||||
}
|
||||
|
||||
static const struct fs_context_operations devpts_context_ops = {
|
||||
.free = devpts_free_fc,
|
||||
.parse_param = devpts_parse_param,
|
||||
.get_tree = devpts_get_tree,
|
||||
.reconfigure = devpts_reconfigure,
|
||||
};
|
||||
|
||||
/*
|
||||
* Set up the filesystem mount context.
|
||||
*/
|
||||
static int devpts_init_fs_context(struct fs_context *fc)
|
||||
{
|
||||
struct pts_fs_info *fsi;
|
||||
|
||||
fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL);
|
||||
if (!fsi)
|
||||
return -ENOMEM;
|
||||
|
||||
ida_init(&fsi->allocated_ptys);
|
||||
fsi->mount_opts.uid = GLOBAL_ROOT_UID;
|
||||
fsi->mount_opts.gid = GLOBAL_ROOT_GID;
|
||||
fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE;
|
||||
fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
|
||||
fsi->mount_opts.max = NR_UNIX98_PTY_MAX;
|
||||
|
||||
if (fc->purpose == FS_CONTEXT_FOR_MOUNT &&
|
||||
current->nsproxy->mnt_ns == init_task.nsproxy->mnt_ns)
|
||||
fsi->mount_opts.reserve = true;
|
||||
|
||||
fc->s_fs_info = fsi;
|
||||
fc->ops = &devpts_context_ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void devpts_kill_sb(struct super_block *sb)
|
||||
@@ -498,7 +466,8 @@ static void devpts_kill_sb(struct super_block *sb)
|
||||
|
||||
static struct file_system_type devpts_fs_type = {
|
||||
.name = "devpts",
|
||||
.mount = devpts_mount,
|
||||
.init_fs_context = devpts_init_fs_context,
|
||||
.parameters = devpts_param_specs,
|
||||
.kill_sb = devpts_kill_sb,
|
||||
.fs_flags = FS_USERNS_MOUNT,
|
||||
};
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/ramfs.h>
|
||||
#include <linux/parser.h>
|
||||
#include <linux/fs_parser.h>
|
||||
#include <linux/fs_context.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/pstore.h>
|
||||
@@ -226,37 +226,38 @@ static struct inode *pstore_get_inode(struct super_block *sb)
|
||||
}
|
||||
|
||||
enum {
|
||||
Opt_kmsg_bytes, Opt_err
|
||||
Opt_kmsg_bytes
|
||||
};
|
||||
|
||||
static const match_table_t tokens = {
|
||||
{Opt_kmsg_bytes, "kmsg_bytes=%u"},
|
||||
{Opt_err, NULL}
|
||||
static const struct fs_parameter_spec pstore_param_spec[] = {
|
||||
fsparam_u32 ("kmsg_bytes", Opt_kmsg_bytes),
|
||||
{}
|
||||
};
|
||||
|
||||
static void parse_options(char *options)
|
||||
struct pstore_context {
|
||||
unsigned int kmsg_bytes;
|
||||
};
|
||||
|
||||
static int pstore_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
{
|
||||
char *p;
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
int option;
|
||||
struct pstore_context *ctx = fc->fs_private;
|
||||
struct fs_parse_result result;
|
||||
int opt;
|
||||
|
||||
if (!options)
|
||||
return;
|
||||
opt = fs_parse(fc, pstore_param_spec, param, &result);
|
||||
/* pstore has historically ignored invalid kmsg_bytes param */
|
||||
if (opt < 0)
|
||||
return 0;
|
||||
|
||||
while ((p = strsep(&options, ",")) != NULL) {
|
||||
int token;
|
||||
|
||||
if (!*p)
|
||||
continue;
|
||||
|
||||
token = match_token(p, tokens, args);
|
||||
switch (token) {
|
||||
case Opt_kmsg_bytes:
|
||||
if (!match_int(&args[0], &option))
|
||||
pstore_set_kmsg_bytes(option);
|
||||
break;
|
||||
}
|
||||
switch (opt) {
|
||||
case Opt_kmsg_bytes:
|
||||
ctx->kmsg_bytes = result.uint_32;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -269,10 +270,12 @@ static int pstore_show_options(struct seq_file *m, struct dentry *root)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pstore_remount(struct super_block *sb, int *flags, char *data)
|
||||
static int pstore_reconfigure(struct fs_context *fc)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
parse_options(data);
|
||||
struct pstore_context *ctx = fc->fs_private;
|
||||
|
||||
sync_filesystem(fc->root->d_sb);
|
||||
pstore_set_kmsg_bytes(ctx->kmsg_bytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -281,7 +284,6 @@ static const struct super_operations pstore_ops = {
|
||||
.statfs = simple_statfs,
|
||||
.drop_inode = generic_delete_inode,
|
||||
.evict_inode = pstore_evict_inode,
|
||||
.remount_fs = pstore_remount,
|
||||
.show_options = pstore_show_options,
|
||||
};
|
||||
|
||||
@@ -406,8 +408,9 @@ void pstore_get_records(int quiet)
|
||||
inode_unlock(d_inode(root));
|
||||
}
|
||||
|
||||
static int pstore_fill_super(struct super_block *sb, void *data, int silent)
|
||||
static int pstore_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
{
|
||||
struct pstore_context *ctx = fc->fs_private;
|
||||
struct inode *inode;
|
||||
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
@@ -417,7 +420,7 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent)
|
||||
sb->s_op = &pstore_ops;
|
||||
sb->s_time_gran = 1;
|
||||
|
||||
parse_options(data);
|
||||
pstore_set_kmsg_bytes(ctx->kmsg_bytes);
|
||||
|
||||
inode = pstore_get_inode(sb);
|
||||
if (inode) {
|
||||
@@ -438,12 +441,26 @@ static int pstore_fill_super(struct super_block *sb, void *data, int silent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dentry *pstore_mount(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data)
|
||||
static int pstore_get_tree(struct fs_context *fc)
|
||||
{
|
||||
return mount_single(fs_type, flags, data, pstore_fill_super);
|
||||
if (fc->root)
|
||||
return pstore_reconfigure(fc);
|
||||
|
||||
return get_tree_single(fc, pstore_fill_super);
|
||||
}
|
||||
|
||||
static void pstore_free_fc(struct fs_context *fc)
|
||||
{
|
||||
kfree(fc->fs_private);
|
||||
}
|
||||
|
||||
static const struct fs_context_operations pstore_context_ops = {
|
||||
.parse_param = pstore_parse_param,
|
||||
.get_tree = pstore_get_tree,
|
||||
.reconfigure = pstore_reconfigure,
|
||||
.free = pstore_free_fc,
|
||||
};
|
||||
|
||||
static void pstore_kill_sb(struct super_block *sb)
|
||||
{
|
||||
guard(mutex)(&pstore_sb_lock);
|
||||
@@ -456,11 +473,33 @@ static void pstore_kill_sb(struct super_block *sb)
|
||||
INIT_LIST_HEAD(&records_list);
|
||||
}
|
||||
|
||||
static int pstore_init_fs_context(struct fs_context *fc)
|
||||
{
|
||||
struct pstore_context *ctx;
|
||||
|
||||
ctx = kzalloc(sizeof(struct pstore_context), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Global kmsg_bytes is initialized to default, and updated
|
||||
* every time we (re)mount the single-sb filesystem with the
|
||||
* option specified.
|
||||
*/
|
||||
ctx->kmsg_bytes = kmsg_bytes;
|
||||
|
||||
fc->fs_private = ctx;
|
||||
fc->ops = &pstore_context_ops;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct file_system_type pstore_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "pstore",
|
||||
.mount = pstore_mount,
|
||||
.kill_sb = pstore_kill_sb,
|
||||
.init_fs_context = pstore_init_fs_context,
|
||||
.parameters = pstore_param_spec,
|
||||
};
|
||||
|
||||
int __init pstore_init_fs(void)
|
||||
|
||||
55
fs/super.c
55
fs/super.c
@@ -1737,61 +1737,6 @@ struct dentry *mount_nodev(struct file_system_type *fs_type,
|
||||
}
|
||||
EXPORT_SYMBOL(mount_nodev);
|
||||
|
||||
int reconfigure_single(struct super_block *s,
|
||||
int flags, void *data)
|
||||
{
|
||||
struct fs_context *fc;
|
||||
int ret;
|
||||
|
||||
/* The caller really need to be passing fc down into mount_single(),
|
||||
* then a chunk of this can be removed. [Bollocks -- AV]
|
||||
* Better yet, reconfiguration shouldn't happen, but rather the second
|
||||
* mount should be rejected if the parameters are not compatible.
|
||||
*/
|
||||
fc = fs_context_for_reconfigure(s->s_root, flags, MS_RMT_MASK);
|
||||
if (IS_ERR(fc))
|
||||
return PTR_ERR(fc);
|
||||
|
||||
ret = parse_monolithic_mount_data(fc, data);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
ret = reconfigure_super(fc);
|
||||
out:
|
||||
put_fs_context(fc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int compare_single(struct super_block *s, void *p)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct dentry *mount_single(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int))
|
||||
{
|
||||
struct super_block *s;
|
||||
int error;
|
||||
|
||||
s = sget(fs_type, compare_single, set_anon_super, flags, NULL);
|
||||
if (IS_ERR(s))
|
||||
return ERR_CAST(s);
|
||||
if (!s->s_root) {
|
||||
error = fill_super(s, data, flags & SB_SILENT ? 1 : 0);
|
||||
if (!error)
|
||||
s->s_flags |= SB_ACTIVE;
|
||||
} else {
|
||||
error = reconfigure_single(s, flags, data);
|
||||
}
|
||||
if (unlikely(error)) {
|
||||
deactivate_locked_super(s);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
return dget(s->s_root);
|
||||
}
|
||||
EXPORT_SYMBOL(mount_single);
|
||||
|
||||
/**
|
||||
* vfs_get_tree - Get the mountable root
|
||||
* @fc: The superblock configuration context.
|
||||
|
||||
@@ -2641,9 +2641,6 @@ static inline bool is_mgtime(const struct inode *inode)
|
||||
extern struct dentry *mount_bdev(struct file_system_type *fs_type,
|
||||
int flags, const char *dev_name, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int));
|
||||
extern struct dentry *mount_single(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int));
|
||||
extern struct dentry *mount_nodev(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *, void *, int));
|
||||
|
||||
@@ -144,8 +144,6 @@ extern void put_fs_context(struct fs_context *fc);
|
||||
extern int vfs_parse_fs_param_source(struct fs_context *fc,
|
||||
struct fs_parameter *param);
|
||||
extern void fc_drop_locked(struct fs_context *fc);
|
||||
int reconfigure_single(struct super_block *s,
|
||||
int flags, void *data);
|
||||
|
||||
extern int get_tree_nodev(struct fs_context *fc,
|
||||
int (*fill_super)(struct super_block *sb,
|
||||
|
||||
Reference in New Issue
Block a user