From 6bbb5b01079dd5b49f8305d8e86d46bbb52b9715 Mon Sep 17 00:00:00 2001 From: meganz009 Date: Sat, 24 Jun 2023 15:57:56 +0800 Subject: [PATCH] devtmpfs: don't mix {ramfs,shmem}_fill_super() with mount_single() commit d401727ea0d7a48eaa01a8089f6b91a8121dcaac upstream. 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 Signed-off-by: Wenya Zhang Reviewed-by: Huang Jian --- drivers/base/devtmpfs.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index f7768077e817..aaf5f416deb8 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c @@ -55,22 +55,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) { @@ -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 */ @@ -420,7 +435,16 @@ static int devtmpfsd(void *p) */ int __init devtmpfs_init(void) { - int err = register_filesystem(&dev_fs_type); + char opts[] = "mode=0755"; + int err; + + mnt = vfs_kern_mount(&internal_fs_type, 0, "devtmpfs", opts); + 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); -- Gitee