Skip to content

Commit

Permalink
devtmpfs: don't mix {ramfs,shmem}_fill_super() with mount_single()
Browse files Browse the repository at this point in the history
Create an internal-only type matching the current devtmpfs, never
register it and have one kernel-internal mount done.  That thing
gets mounted only once, so it is free to use mount_nodev().

The "public" devtmpfs (the one we do register, and only after
the internal mount of the real thing is done) simply gets and
returns an extra reference to the internal superblock.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
  • Loading branch information
Al Viro committed Jul 5, 2019
1 parent 037f11b commit f6ab6e9
Showing 1 changed file with 29 additions and 6 deletions.
35 changes: 29 additions & 6 deletions drivers/base/devtmpfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,22 +56,38 @@ static int __init mount_param(char *str)
}
__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;
atomic_inc(&s->s_active);
down_write(&s->s_umount);
return dget(s->s_root);
}

static struct dentry *dev_mount(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data)
{
#ifdef CONFIG_TMPFS
return mount_single(fs_type, flags, data, shmem_fill_super);
return mount_nodev(fs_type, flags, data, shmem_fill_super);
#else
return mount_single(fs_type, flags, data, ramfs_fill_super);
return ramfs_mount(fs_type, flags, dev_name, data);
#endif
}

static struct file_system_type dev_fs_type = {
static struct file_system_type internal_fs_type = {
.name = "devtmpfs",
.mount = dev_mount,
.kill_sb = kill_litter_super,
};

static struct file_system_type dev_fs_type = {
.name = "devtmpfs",
.mount = public_dev_mount,
};

#ifdef CONFIG_BLOCK
static inline int is_blockdev(struct device *dev)
{
Expand Down Expand Up @@ -378,12 +394,11 @@ static int handle(const char *name, umode_t mode, kuid_t uid, kgid_t gid,

static int devtmpfsd(void *p)
{
char options[] = "mode=0755";
int *err = p;
*err = ksys_unshare(CLONE_NEWNS);
if (*err)
goto out;
*err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, options);
*err = ksys_mount("devtmpfs", "/", "devtmpfs", MS_SILENT, NULL);
if (*err)
goto out;
ksys_chdir("/.."); /* will traverse into overmounted root */
Expand Down Expand Up @@ -420,7 +435,15 @@ static int devtmpfsd(void *p)
*/
int __init devtmpfs_init(void)
{
int err = register_filesystem(&dev_fs_type);
int err;

mnt = vfs_kern_mount(&internal_fs_type, 0, "devtmpfs", "mode=0755");
if (IS_ERR(mnt)) {
printk(KERN_ERR "devtmpfs: unable to create devtmpfs %ld\n",
PTR_ERR(mnt));
return PTR_ERR(mnt);
}
err = register_filesystem(&dev_fs_type);
if (err) {
printk(KERN_ERR "devtmpfs: unable to register devtmpfs "
"type %i\n", err);
Expand Down

0 comments on commit f6ab6e9

Please sign in to comment.