Merge branch 'work.mount3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull more mount API conversions from Al Viro: "Assorted conversions of options parsing to new API. gfs2 is probably the most serious one here; the rest is trivial stuff. Other things in what used to be #work.mount are going to wait for the next cycle (and preferably go via git trees of the filesystems involved)" * 'work.mount3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: gfs2: Convert gfs2 to fs_context vfs: Convert spufs to use the new mount API vfs: Convert hypfs to use the new mount API hypfs: Fix error number left in struct pointer member vfs: Convert functionfs to use the new mount API vfs: Convert bpf to use the new mount API
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/fs_parser.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
@@ -1451,9 +1452,9 @@ struct ffs_sb_fill_data {
|
||||
struct ffs_data *ffs_data;
|
||||
};
|
||||
|
||||
static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
|
||||
static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc)
|
||||
{
|
||||
struct ffs_sb_fill_data *data = _data;
|
||||
struct ffs_sb_fill_data *data = fc->fs_private;
|
||||
struct inode *inode;
|
||||
struct ffs_data *ffs = data->ffs_data;
|
||||
|
||||
@@ -1486,147 +1487,152 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
|
||||
enum {
|
||||
Opt_no_disconnect,
|
||||
Opt_rmode,
|
||||
Opt_fmode,
|
||||
Opt_mode,
|
||||
Opt_uid,
|
||||
Opt_gid,
|
||||
};
|
||||
|
||||
static const struct fs_parameter_spec ffs_fs_param_specs[] = {
|
||||
fsparam_bool ("no_disconnect", Opt_no_disconnect),
|
||||
fsparam_u32 ("rmode", Opt_rmode),
|
||||
fsparam_u32 ("fmode", Opt_fmode),
|
||||
fsparam_u32 ("mode", Opt_mode),
|
||||
fsparam_u32 ("uid", Opt_uid),
|
||||
fsparam_u32 ("gid", Opt_gid),
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct fs_parameter_description ffs_fs_fs_parameters = {
|
||||
.name = "kAFS",
|
||||
.specs = ffs_fs_param_specs,
|
||||
};
|
||||
|
||||
static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param)
|
||||
{
|
||||
struct ffs_sb_fill_data *data = fc->fs_private;
|
||||
struct fs_parse_result result;
|
||||
int opt;
|
||||
|
||||
ENTER();
|
||||
|
||||
if (!opts || !*opts)
|
||||
return 0;
|
||||
opt = fs_parse(fc, &ffs_fs_fs_parameters, param, &result);
|
||||
if (opt < 0)
|
||||
return opt;
|
||||
|
||||
for (;;) {
|
||||
unsigned long value;
|
||||
char *eq, *comma;
|
||||
switch (opt) {
|
||||
case Opt_no_disconnect:
|
||||
data->no_disconnect = result.boolean;
|
||||
break;
|
||||
case Opt_rmode:
|
||||
data->root_mode = (result.uint_32 & 0555) | S_IFDIR;
|
||||
break;
|
||||
case Opt_fmode:
|
||||
data->perms.mode = (result.uint_32 & 0666) | S_IFREG;
|
||||
break;
|
||||
case Opt_mode:
|
||||
data->root_mode = (result.uint_32 & 0555) | S_IFDIR;
|
||||
data->perms.mode = (result.uint_32 & 0666) | S_IFREG;
|
||||
break;
|
||||
|
||||
/* Option limit */
|
||||
comma = strchr(opts, ',');
|
||||
if (comma)
|
||||
*comma = 0;
|
||||
case Opt_uid:
|
||||
data->perms.uid = make_kuid(current_user_ns(), result.uint_32);
|
||||
if (!uid_valid(data->perms.uid))
|
||||
goto unmapped_value;
|
||||
break;
|
||||
case Opt_gid:
|
||||
data->perms.gid = make_kgid(current_user_ns(), result.uint_32);
|
||||
if (!gid_valid(data->perms.gid))
|
||||
goto unmapped_value;
|
||||
break;
|
||||
|
||||
/* Value limit */
|
||||
eq = strchr(opts, '=');
|
||||
if (unlikely(!eq)) {
|
||||
pr_err("'=' missing in %s\n", opts);
|
||||
return -EINVAL;
|
||||
}
|
||||
*eq = 0;
|
||||
|
||||
/* Parse value */
|
||||
if (kstrtoul(eq + 1, 0, &value)) {
|
||||
pr_err("%s: invalid value: %s\n", opts, eq + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Interpret option */
|
||||
switch (eq - opts) {
|
||||
case 13:
|
||||
if (!memcmp(opts, "no_disconnect", 13))
|
||||
data->no_disconnect = !!value;
|
||||
else
|
||||
goto invalid;
|
||||
break;
|
||||
case 5:
|
||||
if (!memcmp(opts, "rmode", 5))
|
||||
data->root_mode = (value & 0555) | S_IFDIR;
|
||||
else if (!memcmp(opts, "fmode", 5))
|
||||
data->perms.mode = (value & 0666) | S_IFREG;
|
||||
else
|
||||
goto invalid;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (!memcmp(opts, "mode", 4)) {
|
||||
data->root_mode = (value & 0555) | S_IFDIR;
|
||||
data->perms.mode = (value & 0666) | S_IFREG;
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
if (!memcmp(opts, "uid", 3)) {
|
||||
data->perms.uid = make_kuid(current_user_ns(), value);
|
||||
if (!uid_valid(data->perms.uid)) {
|
||||
pr_err("%s: unmapped value: %lu\n", opts, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else if (!memcmp(opts, "gid", 3)) {
|
||||
data->perms.gid = make_kgid(current_user_ns(), value);
|
||||
if (!gid_valid(data->perms.gid)) {
|
||||
pr_err("%s: unmapped value: %lu\n", opts, value);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
goto invalid;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
invalid:
|
||||
pr_err("%s: invalid option\n", opts);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Next iteration */
|
||||
if (!comma)
|
||||
break;
|
||||
opts = comma + 1;
|
||||
default:
|
||||
return -ENOPARAM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
unmapped_value:
|
||||
return invalf(fc, "%s: unmapped value: %u", param->key, result.uint_32);
|
||||
}
|
||||
|
||||
/* "mount -t functionfs dev_name /dev/function" ends up here */
|
||||
|
||||
static struct dentry *
|
||||
ffs_fs_mount(struct file_system_type *t, int flags,
|
||||
const char *dev_name, void *opts)
|
||||
/*
|
||||
* Set up the superblock for a mount.
|
||||
*/
|
||||
static int ffs_fs_get_tree(struct fs_context *fc)
|
||||
{
|
||||
struct ffs_sb_fill_data data = {
|
||||
.perms = {
|
||||
.mode = S_IFREG | 0600,
|
||||
.uid = GLOBAL_ROOT_UID,
|
||||
.gid = GLOBAL_ROOT_GID,
|
||||
},
|
||||
.root_mode = S_IFDIR | 0500,
|
||||
.no_disconnect = false,
|
||||
};
|
||||
struct dentry *rv;
|
||||
int ret;
|
||||
struct ffs_sb_fill_data *ctx = fc->fs_private;
|
||||
void *ffs_dev;
|
||||
struct ffs_data *ffs;
|
||||
|
||||
ENTER();
|
||||
|
||||
ret = ffs_fs_parse_opts(&data, opts);
|
||||
if (unlikely(ret < 0))
|
||||
return ERR_PTR(ret);
|
||||
if (!fc->source)
|
||||
return invalf(fc, "No source specified");
|
||||
|
||||
ffs = ffs_data_new(dev_name);
|
||||
ffs = ffs_data_new(fc->source);
|
||||
if (unlikely(!ffs))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
ffs->file_perms = data.perms;
|
||||
ffs->no_disconnect = data.no_disconnect;
|
||||
return -ENOMEM;
|
||||
ffs->file_perms = ctx->perms;
|
||||
ffs->no_disconnect = ctx->no_disconnect;
|
||||
|
||||
ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
|
||||
ffs->dev_name = kstrdup(fc->source, GFP_KERNEL);
|
||||
if (unlikely(!ffs->dev_name)) {
|
||||
ffs_data_put(ffs);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ffs_dev = ffs_acquire_dev(dev_name);
|
||||
ffs_dev = ffs_acquire_dev(ffs->dev_name);
|
||||
if (IS_ERR(ffs_dev)) {
|
||||
ffs_data_put(ffs);
|
||||
return ERR_CAST(ffs_dev);
|
||||
return PTR_ERR(ffs_dev);
|
||||
}
|
||||
ffs->private_data = ffs_dev;
|
||||
data.ffs_data = ffs;
|
||||
|
||||
rv = mount_nodev(t, flags, &data, ffs_sb_fill);
|
||||
if (IS_ERR(rv) && data.ffs_data) {
|
||||
ffs_release_dev(data.ffs_data);
|
||||
ffs_data_put(data.ffs_data);
|
||||
ffs->private_data = ffs_dev;
|
||||
ctx->ffs_data = ffs;
|
||||
return get_tree_nodev(fc, ffs_sb_fill);
|
||||
}
|
||||
|
||||
static void ffs_fs_free_fc(struct fs_context *fc)
|
||||
{
|
||||
struct ffs_sb_fill_data *ctx = fc->fs_private;
|
||||
|
||||
if (ctx) {
|
||||
if (ctx->ffs_data) {
|
||||
ffs_release_dev(ctx->ffs_data);
|
||||
ffs_data_put(ctx->ffs_data);
|
||||
}
|
||||
|
||||
kfree(ctx);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static const struct fs_context_operations ffs_fs_context_ops = {
|
||||
.free = ffs_fs_free_fc,
|
||||
.parse_param = ffs_fs_parse_param,
|
||||
.get_tree = ffs_fs_get_tree,
|
||||
};
|
||||
|
||||
static int ffs_fs_init_fs_context(struct fs_context *fc)
|
||||
{
|
||||
struct ffs_sb_fill_data *ctx;
|
||||
|
||||
ctx = kzalloc(sizeof(struct ffs_sb_fill_data), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->perms.mode = S_IFREG | 0600;
|
||||
ctx->perms.uid = GLOBAL_ROOT_UID;
|
||||
ctx->perms.gid = GLOBAL_ROOT_GID;
|
||||
ctx->root_mode = S_IFDIR | 0500;
|
||||
ctx->no_disconnect = false;
|
||||
|
||||
fc->fs_private = ctx;
|
||||
fc->ops = &ffs_fs_context_ops;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1644,7 +1650,8 @@ ffs_fs_kill_sb(struct super_block *sb)
|
||||
static struct file_system_type ffs_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "functionfs",
|
||||
.mount = ffs_fs_mount,
|
||||
.init_fs_context = ffs_fs_init_fs_context,
|
||||
.parameters = &ffs_fs_fs_parameters,
|
||||
.kill_sb = ffs_fs_kill_sb,
|
||||
};
|
||||
MODULE_ALIAS_FS("functionfs");
|
||||
|
Reference in New Issue
Block a user