Merge branch 'work.mount0' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull vfs mount updates from Al Viro:
 "The first part of mount updates.

  Convert filesystems to use the new mount API"

* 'work.mount0' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (63 commits)
  mnt_init(): call shmem_init() unconditionally
  constify ksys_mount() string arguments
  don't bother with registering rootfs
  init_rootfs(): don't bother with init_ramfs_fs()
  vfs: Convert smackfs to use the new mount API
  vfs: Convert selinuxfs to use the new mount API
  vfs: Convert securityfs to use the new mount API
  vfs: Convert apparmorfs to use the new mount API
  vfs: Convert openpromfs to use the new mount API
  vfs: Convert xenfs to use the new mount API
  vfs: Convert gadgetfs to use the new mount API
  vfs: Convert oprofilefs to use the new mount API
  vfs: Convert ibmasmfs to use the new mount API
  vfs: Convert qib_fs/ipathfs to use the new mount API
  vfs: Convert efivarfs to use the new mount API
  vfs: Convert configfs to use the new mount API
  vfs: Convert binfmt_misc to use the new mount API
  convenience helper: get_tree_single()
  convenience helper get_tree_nodev()
  vfs: Kill sget_userns()
  ...
This commit is contained in:
Linus Torvalds
2019-07-19 10:42:02 -07:00
60 changed files with 584 additions and 536 deletions

View File

@@ -42,6 +42,7 @@
#include <linux/ramfs.h>
#include <linux/percpu-refcount.h>
#include <linux/mount.h>
#include <linux/pseudo_fs.h>
#include <asm/kmap_types.h>
#include <linux/uaccess.h>
@@ -249,15 +250,12 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
return file;
}
static struct dentry *aio_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int aio_init_fs_context(struct fs_context *fc)
{
struct dentry *root = mount_pseudo(fs_type, "aio:", NULL, NULL,
AIO_RING_MAGIC);
if (!IS_ERR(root))
root->d_sb->s_iflags |= SB_I_NOEXEC;
return root;
if (!init_pseudo(fc, AIO_RING_MAGIC))
return -ENOMEM;
fc->s_iflags |= SB_I_NOEXEC;
return 0;
}
/* aio_setup
@@ -268,7 +266,7 @@ static int __init aio_setup(void)
{
static struct file_system_type aio_fs = {
.name = "aio",
.mount = aio_mount,
.init_fs_context = aio_init_fs_context,
.kill_sb = kill_anon_super,
};
aio_mnt = kern_mount(&aio_fs);

View File

@@ -20,6 +20,7 @@
#include <linux/kernel.h>
#include <linux/magic.h>
#include <linux/anon_inodes.h>
#include <linux/pseudo_fs.h>
#include <linux/uaccess.h>
@@ -39,16 +40,18 @@ static const struct dentry_operations anon_inodefs_dentry_operations = {
.d_dname = anon_inodefs_dname,
};
static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int anon_inodefs_init_fs_context(struct fs_context *fc)
{
return mount_pseudo(fs_type, "anon_inode:", NULL,
&anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC);
struct pseudo_fs_context *ctx = init_pseudo(fc, ANON_INODE_FS_MAGIC);
if (!ctx)
return -ENOMEM;
ctx->dops = &anon_inodefs_dentry_operations;
return 0;
}
static struct file_system_type anon_inode_fs_type = {
.name = "anon_inodefs",
.mount = anon_inodefs_mount,
.init_fs_context = anon_inodefs_init_fs_context,
.kill_sb = kill_anon_super,
};

View File

@@ -23,6 +23,7 @@
#include <linux/pagemap.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/fs_context.h>
#include <linux/syscalls.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
@@ -821,7 +822,7 @@ static const struct super_operations s_ops = {
.evict_inode = bm_evict_inode,
};
static int bm_fill_super(struct super_block *sb, void *data, int silent)
static int bm_fill_super(struct super_block *sb, struct fs_context *fc)
{
int err;
static const struct tree_descr bm_files[] = {
@@ -836,10 +837,19 @@ static int bm_fill_super(struct super_block *sb, void *data, int silent)
return err;
}
static struct dentry *bm_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int bm_get_tree(struct fs_context *fc)
{
return mount_single(fs_type, flags, data, bm_fill_super);
return get_tree_single(fc, bm_fill_super);
}
static const struct fs_context_operations bm_context_ops = {
.get_tree = bm_get_tree,
};
static int bm_init_fs_context(struct fs_context *fc)
{
fc->ops = &bm_context_ops;
return 0;
}
static struct linux_binfmt misc_format = {
@@ -850,7 +860,7 @@ static struct linux_binfmt misc_format = {
static struct file_system_type bm_fs_type = {
.owner = THIS_MODULE,
.name = "binfmt_misc",
.mount = bm_mount,
.init_fs_context = bm_init_fs_context,
.kill_sb = kill_litter_super,
};
MODULE_ALIAS_FS("binfmt_misc");

View File

@@ -26,6 +26,7 @@
#include <linux/writeback.h>
#include <linux/mpage.h>
#include <linux/mount.h>
#include <linux/pseudo_fs.h>
#include <linux/uio.h>
#include <linux/namei.h>
#include <linux/log2.h>
@@ -821,19 +822,19 @@ static const struct super_operations bdev_sops = {
.evict_inode = bdev_evict_inode,
};
static struct dentry *bd_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int bd_init_fs_context(struct fs_context *fc)
{
struct dentry *dent;
dent = mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC);
if (!IS_ERR(dent))
dent->d_sb->s_iflags |= SB_I_CGROUPWB;
return dent;
struct pseudo_fs_context *ctx = init_pseudo(fc, BDEVFS_MAGIC);
if (!ctx)
return -ENOMEM;
fc->s_iflags |= SB_I_CGROUPWB;
ctx->ops = &bdev_sops;
return 0;
}
static struct file_system_type bd_type = {
.name = "bdev",
.mount = bd_mount,
.init_fs_context = bd_init_fs_context,
.kill_sb = kill_anon_super,
};

View File

@@ -5,6 +5,7 @@
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/pseudo_fs.h>
#include <linux/magic.h>
#include "btrfs-tests.h"
#include "../ctree.h"
@@ -32,17 +33,19 @@ static const struct super_operations btrfs_test_super_ops = {
.destroy_inode = btrfs_test_destroy_inode,
};
static struct dentry *btrfs_test_mount(struct file_system_type *fs_type,
int flags, const char *dev_name,
void *data)
static int btrfs_test_init_fs_context(struct fs_context *fc)
{
return mount_pseudo(fs_type, "btrfs_test:", &btrfs_test_super_ops,
NULL, BTRFS_TEST_MAGIC);
struct pseudo_fs_context *ctx = init_pseudo(fc, BTRFS_TEST_MAGIC);
if (!ctx)
return -ENOMEM;
ctx->ops = &btrfs_test_super_ops;
return 0;
}
static struct file_system_type test_type = {
.name = "btrfs_test_fs",
.mount = btrfs_test_mount,
.init_fs_context = btrfs_test_init_fs_context,
.kill_sb = kill_anon_super,
};

View File

@@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/fs_context.h>
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -52,7 +53,7 @@ static struct configfs_dirent configfs_root = {
.s_iattr = NULL,
};
static int configfs_fill_super(struct super_block *sb, void *data, int silent)
static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct inode *inode;
struct dentry *root;
@@ -88,16 +89,25 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
static struct dentry *configfs_do_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int configfs_get_tree(struct fs_context *fc)
{
return mount_single(fs_type, flags, data, configfs_fill_super);
return get_tree_single(fc, configfs_fill_super);
}
static const struct fs_context_operations configfs_context_ops = {
.get_tree = configfs_get_tree,
};
static int configfs_init_fs_context(struct fs_context *fc)
{
fc->ops = &configfs_context_ops;
return 0;
}
static struct file_system_type configfs_fs_type = {
.owner = THIS_MODULE,
.name = "configfs",
.mount = configfs_do_mount,
.init_fs_context = configfs_init_fs_context,
.kill_sb = kill_litter_super,
};
MODULE_ALIAS_FS("configfs");

View File

@@ -316,7 +316,6 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
end = ERR_PTR(-ENAMETOOLONG);
return end;
}
EXPORT_SYMBOL(simple_dname);
/*
* Write full pathname from the root of the filesystem into the buffer.

View File

@@ -7,6 +7,7 @@
#include <linux/ctype.h>
#include <linux/efi.h>
#include <linux/fs.h>
#include <linux/fs_context.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/ucs2_string.h>
@@ -28,8 +29,6 @@ static const struct super_operations efivarfs_ops = {
.evict_inode = efivarfs_evict_inode,
};
static struct super_block *efivarfs_sb;
/*
* Compare two efivarfs file names.
*
@@ -188,14 +187,12 @@ static int efivarfs_destroy(struct efivar_entry *entry, void *data)
return 0;
}
static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct inode *inode = NULL;
struct dentry *root;
int err;
efivarfs_sb = sb;
sb->s_maxbytes = MAX_LFS_FILESIZE;
sb->s_blocksize = PAGE_SIZE;
sb->s_blocksize_bits = PAGE_SHIFT;
@@ -223,16 +220,24 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
return err;
}
static struct dentry *efivarfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int efivarfs_get_tree(struct fs_context *fc)
{
return mount_single(fs_type, flags, data, efivarfs_fill_super);
return get_tree_single(fc, efivarfs_fill_super);
}
static const struct fs_context_operations efivarfs_context_ops = {
.get_tree = efivarfs_get_tree,
};
static int efivarfs_init_fs_context(struct fs_context *fc)
{
fc->ops = &efivarfs_context_ops;
return 0;
}
static void efivarfs_kill_sb(struct super_block *sb)
{
kill_litter_super(sb);
efivarfs_sb = NULL;
/* Remove all entries and destroy */
__efivar_entry_iter(efivarfs_destroy, &efivarfs_list, NULL, NULL);
@@ -241,7 +246,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
static struct file_system_type efivarfs_type = {
.owner = THIS_MODULE,
.name = "efivarfs",
.mount = efivarfs_mount,
.init_fs_context = efivarfs_init_fs_context,
.kill_sb = efivarfs_kill_sb,
};

View File

@@ -264,6 +264,7 @@ int fs_lookup_param(struct fs_context *fc,
return invalf(fc, "%s: not usable as path", param->key);
}
f->refcnt++; /* filename_lookup() drops our ref. */
ret = filename_lookup(param->dirfd, f, flags, _path, NULL);
if (ret < 0) {
errorf(fc, "%s: Lookup failure for '%s'", param->key, f->name);

View File

@@ -226,6 +226,8 @@ static int vfs_fsconfig_locked(struct fs_context *fc, int cmd,
case FSCONFIG_CMD_CREATE:
if (fc->phase != FS_CONTEXT_CREATE_PARAMS)
return -EBUSY;
if (!mount_capable(fc))
return -EPERM;
fc->phase = FS_CONTEXT_CREATING;
ret = vfs_get_tree(fc);
if (ret)

View File

@@ -346,7 +346,7 @@ static int fuse_ctl_fill_super(struct super_block *sb, struct fs_context *fctx)
static int fuse_ctl_get_tree(struct fs_context *fc)
{
return vfs_get_super(fc, vfs_get_single_super, fuse_ctl_fill_super);
return get_tree_single(fc, fuse_ctl_fill_super);
}
static const struct fs_context_operations fuse_ctl_context_ops = {

View File

@@ -1299,7 +1299,7 @@ static int hugetlbfs_get_tree(struct fs_context *fc)
int err = hugetlbfs_validate(fc);
if (err)
return err;
return vfs_get_super(fc, vfs_get_independent_super, hugetlbfs_fill_super);
return get_tree_nodev(fc, hugetlbfs_fill_super);
}
static void hugetlbfs_fs_context_free(struct fs_context *fc)

View File

@@ -14,6 +14,7 @@ struct path;
struct mount;
struct shrink_control;
struct fs_context;
struct user_namespace;
/*
* block_dev.c
@@ -107,6 +108,7 @@ extern struct file *alloc_empty_file_noaccount(int, const struct cred *);
extern int reconfigure_super(struct fs_context *);
extern bool trylock_super(struct super_block *sb);
extern struct super_block *user_get_super(dev_t);
extern bool mount_capable(struct fs_context *);
/*
* open.c
@@ -154,6 +156,7 @@ extern int d_set_mounted(struct dentry *dentry);
extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc);
extern struct dentry *d_alloc_cursor(struct dentry *);
extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *);
extern char *simple_dname(struct dentry *, char *, int);
/*
* read_write.c

View File

@@ -17,6 +17,8 @@
#include <linux/exportfs.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> /* sync_mapping_buffers */
#include <linux/fs_context.h>
#include <linux/pseudo_fs.h>
#include <linux/uaccess.h>
@@ -236,34 +238,22 @@ static const struct super_operations simple_super_operations = {
.statfs = simple_statfs,
};
/*
* Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
* will never be mountable)
*/
struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
const struct super_operations *ops, const struct xattr_handler **xattr,
const struct dentry_operations *dops, unsigned long magic)
static int pseudo_fs_fill_super(struct super_block *s, struct fs_context *fc)
{
struct super_block *s;
struct dentry *dentry;
struct pseudo_fs_context *ctx = fc->fs_private;
struct inode *root;
struct qstr d_name = QSTR_INIT(name, strlen(name));
s = sget_userns(fs_type, NULL, set_anon_super, SB_KERNMOUNT|SB_NOUSER,
&init_user_ns, NULL);
if (IS_ERR(s))
return ERR_CAST(s);
s->s_maxbytes = MAX_LFS_FILESIZE;
s->s_blocksize = PAGE_SIZE;
s->s_blocksize_bits = PAGE_SHIFT;
s->s_magic = magic;
s->s_op = ops ? ops : &simple_super_operations;
s->s_xattr = xattr;
s->s_magic = ctx->magic;
s->s_op = ctx->ops ?: &simple_super_operations;
s->s_xattr = ctx->xattr;
s->s_time_gran = 1;
root = new_inode(s);
if (!root)
goto Enomem;
return -ENOMEM;
/*
* since this is the first inode, make it number 1. New inodes created
* after this must take care not to collide with it (by passing
@@ -272,22 +262,48 @@ struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
root->i_ino = 1;
root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR;
root->i_atime = root->i_mtime = root->i_ctime = current_time(root);
dentry = __d_alloc(s, &d_name);
if (!dentry) {
iput(root);
goto Enomem;
}
d_instantiate(dentry, root);
s->s_root = dentry;
s->s_d_op = dops;
s->s_flags |= SB_ACTIVE;
return dget(s->s_root);
Enomem:
deactivate_locked_super(s);
return ERR_PTR(-ENOMEM);
s->s_root = d_make_root(root);
if (!s->s_root)
return -ENOMEM;
s->s_d_op = ctx->dops;
return 0;
}
EXPORT_SYMBOL(mount_pseudo_xattr);
static int pseudo_fs_get_tree(struct fs_context *fc)
{
return get_tree_nodev(fc, pseudo_fs_fill_super);
}
static void pseudo_fs_free(struct fs_context *fc)
{
kfree(fc->fs_private);
}
static const struct fs_context_operations pseudo_fs_context_ops = {
.free = pseudo_fs_free,
.get_tree = pseudo_fs_get_tree,
};
/*
* Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
* will never be mountable)
*/
struct pseudo_fs_context *init_pseudo(struct fs_context *fc,
unsigned long magic)
{
struct pseudo_fs_context *ctx;
ctx = kzalloc(sizeof(struct pseudo_fs_context), GFP_KERNEL);
if (likely(ctx)) {
ctx->magic = magic;
fc->fs_private = ctx;
fc->ops = &pseudo_fs_context_ops;
fc->sb_flags |= SB_NOUSER;
fc->global = true;
}
return ctx;
}
EXPORT_SYMBOL(init_pseudo);
int simple_open(struct inode *inode, struct file *file)
{

View File

@@ -29,6 +29,7 @@
#include <linux/sched/task.h>
#include <uapi/linux/mount.h>
#include <linux/fs_context.h>
#include <linux/shmem_fs.h>
#include "pnode.h"
#include "internal.h"
@@ -2788,6 +2789,8 @@ static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
err = vfs_parse_fs_string(fc, "source", name, strlen(name));
if (!err)
err = parse_monolithic_mount_data(fc, data);
if (!err && !mount_capable(fc))
err = -EPERM;
if (!err)
err = vfs_get_tree(fc);
if (!err)
@@ -3295,8 +3298,8 @@ struct dentry *mount_subtree(struct vfsmount *m, const char *name)
}
EXPORT_SYMBOL(mount_subtree);
int ksys_mount(char __user *dev_name, char __user *dir_name, char __user *type,
unsigned long flags, void __user *data)
int ksys_mount(const char __user *dev_name, const char __user *dir_name,
const char __user *type, unsigned long flags, void __user *data)
{
int ret;
char *kernel_type;
@@ -3687,13 +3690,8 @@ static void __init init_mount_tree(void)
struct mount *m;
struct mnt_namespace *ns;
struct path root;
struct file_system_type *type;
type = get_fs_type("rootfs");
if (!type)
panic("Can't find rootfs type");
mnt = vfs_kern_mount(type, 0, "rootfs", NULL);
put_filesystem(type);
mnt = vfs_kern_mount(&rootfs_fs_type, 0, "rootfs", NULL);
if (IS_ERR(mnt))
panic("Can't create rootfs");
@@ -3746,6 +3744,7 @@ void __init mnt_init(void)
fs_kobj = kobject_create_and_add("fs", NULL);
if (!fs_kobj)
printk(KERN_WARNING "%s: kobj create error\n", __func__);
shmem_init();
init_rootfs();
init_mount_tree();
}

View File

@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <linux/namei.h>
#include <linux/ctype.h>
#include <linux/fs_context.h>
#include <linux/sunrpc/svcsock.h>
#include <linux/lockd/lockd.h>
@@ -1337,7 +1338,7 @@ void nfsd_client_rmdir(struct dentry *dentry)
inode_unlock(dir);
}
static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
nfsd_net_id);
@@ -1372,7 +1373,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
#endif
/* last one */ {""}
};
get_net(sb->s_fs_info);
ret = simple_fill_super(sb, 0x6e667364, nfsd_files);
if (ret)
return ret;
@@ -1381,14 +1382,31 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
return PTR_ERR(dentry);
nn->nfsd_client_dir = dentry;
return 0;
}
static struct dentry *nfsd_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int nfsd_fs_get_tree(struct fs_context *fc)
{
struct net *net = current->nsproxy->net_ns;
return mount_ns(fs_type, flags, data, net, net->user_ns, nfsd_fill_super);
fc->s_fs_info = get_net(fc->net_ns);
return vfs_get_super(fc, vfs_get_keyed_super, nfsd_fill_super);
}
static void nfsd_fs_free_fc(struct fs_context *fc)
{
if (fc->s_fs_info)
put_net(fc->s_fs_info);
}
static const struct fs_context_operations nfsd_fs_context_ops = {
.free = nfsd_fs_free_fc,
.get_tree = nfsd_fs_get_tree,
};
static int nfsd_init_fs_context(struct fs_context *fc)
{
put_user_ns(fc->user_ns);
fc->user_ns = get_user_ns(fc->net_ns->user_ns);
fc->ops = &nfsd_fs_context_ops;
return 0;
}
static void nfsd_umount(struct super_block *sb)
@@ -1402,7 +1420,7 @@ static void nfsd_umount(struct super_block *sb)
static struct file_system_type nfsd_fs_type = {
.owner = THIS_MODULE,
.name = "nfsd",
.mount = nfsd_mount,
.init_fs_context = nfsd_init_fs_context,
.kill_sb = nfsd_umount,
};
MODULE_ALIAS_FS("nfsd");

View File

@@ -1,5 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/mount.h>
#include <linux/pseudo_fs.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/proc_ns.h>
@@ -258,15 +259,20 @@ static const struct super_operations nsfs_ops = {
.evict_inode = nsfs_evict,
.show_path = nsfs_show_path,
};
static struct dentry *nsfs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int nsfs_init_fs_context(struct fs_context *fc)
{
return mount_pseudo(fs_type, "nsfs:", &nsfs_ops,
&ns_dentry_operations, NSFS_MAGIC);
struct pseudo_fs_context *ctx = init_pseudo(fc, NSFS_MAGIC);
if (!ctx)
return -ENOMEM;
ctx->ops = &nsfs_ops;
ctx->dops = &ns_dentry_operations;
return 0;
}
static struct file_system_type nsfs = {
.name = "nsfs",
.mount = nsfs_mount,
.init_fs_context = nsfs_init_fs_context,
.kill_sb = kill_anon_super,
};

View File

@@ -9,6 +9,7 @@
#include <linux/types.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/fs_context.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
@@ -375,7 +376,7 @@ static const struct super_operations openprom_sops = {
.remount_fs = openprom_remount,
};
static int openprom_fill_super(struct super_block *s, void *data, int silent)
static int openprom_fill_super(struct super_block *s, struct fs_context *fc)
{
struct inode *root_inode;
struct op_inode_info *oi;
@@ -409,16 +410,25 @@ out_no_root:
return ret;
}
static struct dentry *openprom_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int openpromfs_get_tree(struct fs_context *fc)
{
return mount_single(fs_type, flags, data, openprom_fill_super);
return get_tree_single(fc, openprom_fill_super);
}
static const struct fs_context_operations openpromfs_context_ops = {
.get_tree = openpromfs_get_tree,
};
static int openpromfs_init_fs_context(struct fs_context *fc)
{
fc->ops = &openpromfs_context_ops;
return 0;
}
static struct file_system_type openprom_fs_type = {
.owner = THIS_MODULE,
.name = "openpromfs",
.mount = openprom_mount,
.init_fs_context = openpromfs_init_fs_context,
.kill_sb = kill_anon_super,
};
MODULE_ALIAS_FS("openpromfs");

View File

@@ -14,6 +14,7 @@
#include <linux/fs.h>
#include <linux/log2.h>
#include <linux/mount.h>
#include <linux/pseudo_fs.h>
#include <linux/magic.h>
#include <linux/pipe_fs_i.h>
#include <linux/uio.h>
@@ -1182,16 +1183,20 @@ static const struct super_operations pipefs_ops = {
* any operations on the root directory. However, we need a non-trivial
* d_name - pipe: will go nicely and kill the special-casing in procfs.
*/
static struct dentry *pipefs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
static int pipefs_init_fs_context(struct fs_context *fc)
{
return mount_pseudo(fs_type, "pipe:", &pipefs_ops,
&pipefs_dentry_operations, PIPEFS_MAGIC);
struct pseudo_fs_context *ctx = init_pseudo(fc, PIPEFS_MAGIC);
if (!ctx)
return -ENOMEM;
ctx->ops = &pipefs_ops;
ctx->dops = &pipefs_dentry_operations;
return 0;
}
static struct file_system_type pipe_fs_type = {
.name = "pipefs",
.mount = pipefs_mount,
.init_fs_context = pipefs_init_fs_context,
.kill_sb = kill_anon_super,
};

View File

@@ -157,8 +157,6 @@ static int proc_get_tree(struct fs_context *fc)
{
struct proc_fs_context *ctx = fc->fs_private;
put_user_ns(fc->user_ns);
fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
fc->s_fs_info = ctx->pid_ns;
return vfs_get_super(fc, vfs_get_keyed_super, proc_fill_super);
}
@@ -167,8 +165,7 @@ static void proc_fs_context_free(struct fs_context *fc)
{
struct proc_fs_context *ctx = fc->fs_private;
if (ctx->pid_ns)
put_pid_ns(ctx->pid_ns);
put_pid_ns(ctx->pid_ns);
kfree(ctx);
}
@@ -188,6 +185,8 @@ static int proc_init_fs_context(struct fs_context *fc)
return -ENOMEM;
ctx->pid_ns = get_pid_ns(task_active_pid_ns(current));
put_user_ns(fc->user_ns);
fc->user_ns = get_user_ns(ctx->pid_ns->user_ns);
fc->fs_private = ctx;
fc->ops = &proc_fs_context_ops;
return 0;

View File

@@ -266,12 +266,8 @@ static struct file_system_type ramfs_fs_type = {
.fs_flags = FS_USERNS_MOUNT,
};
int __init init_ramfs_fs(void)
static int __init init_ramfs_fs(void)
{
static unsigned long once;
if (test_and_set_bit(0, &once))
return 0;
return register_filesystem(&ramfs_fs_type);
}
fs_initcall(init_ramfs_fs);

View File

@@ -476,6 +476,17 @@ void generic_shutdown_super(struct super_block *sb)
EXPORT_SYMBOL(generic_shutdown_super);
bool mount_capable(struct fs_context *fc)
{
struct user_namespace *user_ns = fc->global ? &init_user_ns
: fc->user_ns;
if (!(fc->fs_type->fs_flags & FS_USERNS_MOUNT))
return capable(CAP_SYS_ADMIN);
else
return ns_capable(user_ns, CAP_SYS_ADMIN);
}
/**
* sget_fc - Find or create a superblock
* @fc: Filesystem context.
@@ -503,20 +514,6 @@ struct super_block *sget_fc(struct fs_context *fc,
struct user_namespace *user_ns = fc->global ? &init_user_ns : fc->user_ns;
int err;
if (!(fc->sb_flags & SB_KERNMOUNT) &&
fc->purpose != FS_CONTEXT_FOR_SUBMOUNT) {
/* Don't allow mounting unless the caller has CAP_SYS_ADMIN
* over the namespace.
*/
if (!(fc->fs_type->fs_flags & FS_USERNS_MOUNT)) {
if (!capable(CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
} else {
if (!ns_capable(fc->user_ns, CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
}
}
retry:
spin_lock(&sb_lock);
if (test) {
@@ -543,6 +540,7 @@ retry:
}
fc->s_fs_info = NULL;
s->s_type = fc->fs_type;
s->s_iflags |= fc->s_iflags;
strlcpy(s->s_id, s->s_type->name, sizeof(s->s_id));
list_add_tail(&s->s_list, &super_blocks);
hlist_add_head(&s->s_instances, &s->s_type->fs_supers);
@@ -565,28 +563,31 @@ share_extant_sb:
EXPORT_SYMBOL(sget_fc);
/**
* sget_userns - find or create a superblock
* @type: filesystem type superblock should belong to
* @test: comparison callback
* @set: setup callback
* @flags: mount flags
* @user_ns: User namespace for the super_block
* @data: argument to each of them
* sget - find or create a superblock
* @type: filesystem type superblock should belong to
* @test: comparison callback
* @set: setup callback
* @flags: mount flags
* @data: argument to each of them
*/
struct super_block *sget_userns(struct file_system_type *type,
struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
int flags, struct user_namespace *user_ns,
int flags,
void *data)
{
struct user_namespace *user_ns = current_user_ns();
struct super_block *s = NULL;
struct super_block *old;
int err;
if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) &&
!(type->fs_flags & FS_USERNS_MOUNT) &&
!capable(CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
/* We don't yet pass the user namespace of the parent
* mount through to here so always use &init_user_ns
* until that changes.
*/
if (flags & SB_SUBMOUNT)
user_ns = &init_user_ns;
retry:
spin_lock(&sb_lock);
if (test) {
@@ -627,39 +628,6 @@ retry:
register_shrinker_prepared(&s->s_shrink);
return s;
}
EXPORT_SYMBOL(sget_userns);
/**
* sget - find or create a superblock
* @type: filesystem type superblock should belong to
* @test: comparison callback
* @set: setup callback
* @flags: mount flags
* @data: argument to each of them
*/
struct super_block *sget(struct file_system_type *type,
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
int flags,
void *data)
{
struct user_namespace *user_ns = current_user_ns();
/* We don't yet pass the user namespace of the parent
* mount through to here so always use &init_user_ns
* until that changes.
*/
if (flags & SB_SUBMOUNT)
user_ns = &init_user_ns;
/* Ensure the requestor has permissions over the target filesystem */
if (!(flags & (SB_KERNMOUNT|SB_SUBMOUNT)) && !ns_capable(user_ns, CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
return sget_userns(type, test, set, flags, user_ns, data);
}
EXPORT_SYMBOL(sget);
void drop_super(struct super_block *sb)
@@ -1147,50 +1115,6 @@ void kill_litter_super(struct super_block *sb)
}
EXPORT_SYMBOL(kill_litter_super);
static int ns_test_super(struct super_block *sb, void *data)
{
return sb->s_fs_info == data;
}
static int ns_set_super(struct super_block *sb, void *data)
{
sb->s_fs_info = data;
return set_anon_super(sb, NULL);
}
struct dentry *mount_ns(struct file_system_type *fs_type,
int flags, void *data, void *ns, struct user_namespace *user_ns,
int (*fill_super)(struct super_block *, void *, int))
{
struct super_block *sb;
/* Don't allow mounting unless the caller has CAP_SYS_ADMIN
* over the namespace.
*/
if (!(flags & SB_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags,
user_ns, ns);
if (IS_ERR(sb))
return ERR_CAST(sb);
if (!sb->s_root) {
int err;
err = fill_super(sb, data, flags & SB_SILENT ? 1 : 0);
if (err) {
deactivate_locked_super(sb);
return ERR_PTR(err);
}
sb->s_flags |= SB_ACTIVE;
}
return dget(sb->s_root);
}
EXPORT_SYMBOL(mount_ns);
int set_anon_super_fc(struct super_block *sb, struct fs_context *fc)
{
return set_anon_super(sb, NULL);
@@ -1274,6 +1198,22 @@ int vfs_get_super(struct fs_context *fc,
}
EXPORT_SYMBOL(vfs_get_super);
int get_tree_nodev(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc))
{
return vfs_get_super(fc, vfs_get_independent_super, fill_super);
}
EXPORT_SYMBOL(get_tree_nodev);
int get_tree_single(struct fs_context *fc,
int (*fill_super)(struct super_block *sb,
struct fs_context *fc))
{
return vfs_get_super(fc, vfs_get_single_super, fill_super);
}
EXPORT_SYMBOL(get_tree_single);
#ifdef CONFIG_BLOCK
static int set_bdev_super(struct super_block *s, void *data)
{

View File

@@ -72,8 +72,7 @@ static int sysfs_init_fs_context(struct fs_context *fc)
fc->fs_private = kfc;
fc->ops = &sysfs_fs_context_ops;
if (netns) {
if (fc->user_ns)
put_user_ns(fc->user_ns);
put_user_ns(fc->user_ns);
fc->user_ns = get_user_ns(netns->user_ns);
}
fc->global = true;