static int devpts_fill_super(struct super_block *s, void *data, int silent) { struct inode *inode; int error; s->s_iflags &= ~SB_I_NODEV; s->s_blocksize = 1024; s->s_blocksize_bits = 10; s->s_magic = DEVPTS_SUPER_MAGIC; s->s_op = &devpts_sops; s->s_time_gran = 1; 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; inode->i_ino = 1; inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; set_nlink(inode, 2); s->s_root = d_make_root(inode); if (!s->s_root) { pr_err("get root dentry failed\n"); goto fail; } error = mknod_ptmx(s); if (error) goto fail_dput; return 0; fail_dput: dput(s->s_root); s->s_root = NULL; fail: return error; }
/* * devpts_mount() * * If the '-o newinstance' mount option was specified, mount a new * (private) instance of devpts. PTYs created in this instance are * independent of the PTYs in other devpts instances. * * If the '-o newinstance' option was not specified, mount/remount the * initial kernel mount of devpts. This type of mount gives the * legacy, single-instance semantics. * * The 'newinstance' option is needed to support multiple namespace * semantics in devpts while preserving backward compatibility of the * current 'single-namespace' semantics. i.e all mounts of devpts * without the 'newinstance' mount option should bind to the initial * kernel mount, like mount_single(). * * Mounts with 'newinstance' option create a new, private namespace. * * NOTE: * * For single-mount semantics, devpts cannot use mount_single(), * because mount_single()/sget() find and use the super-block from * the most recent mount of devpts. But that recent mount may be a * 'newinstance' mount and mount_single() would pick the newinstance * super-block instead of the initial super-block. */ static struct dentry *devpts_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { int error; struct pts_mount_opts opts; struct super_block *s; error = parse_mount_options(data, PARSE_MOUNT, &opts); if (error) return ERR_PTR(error); /* Require newinstance for all user namespace mounts to ensure * the mount options are not changed. */ if ((current_user_ns() != &init_user_ns) && !opts.newinstance) return ERR_PTR(-EINVAL); if (opts.newinstance) s = sget(fs_type, NULL, set_anon_super, flags, NULL); else s = sget(fs_type, compare_init_pts_sb, set_anon_super, flags, NULL); if (IS_ERR(s)) return ERR_CAST(s); if (!s->s_root) { error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (error) goto out_undo_sget; s->s_flags |= MS_ACTIVE; } memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts)); error = mknod_ptmx(s); if (error) goto out_undo_sget; return dget(s->s_root); out_undo_sget: deactivate_locked_super(s); return ERR_PTR(error); }
/* * devpts_get_sb() * * If the '-o newinstance' mount option was specified, mount a new * (private) instance of devpts. PTYs created in this instance are * independent of the PTYs in other devpts instances. * * If the '-o newinstance' option was not specified, mount/remount the * initial kernel mount of devpts. This type of mount gives the * legacy, single-instance semantics. * * The 'newinstance' option is needed to support multiple namespace * semantics in devpts while preserving backward compatibility of the * current 'single-namespace' semantics. i.e all mounts of devpts * without the 'newinstance' mount option should bind to the initial * kernel mount, like get_sb_single(). * * Mounts with 'newinstance' option create a new, private namespace. * * NOTE: * * For single-mount semantics, devpts cannot use get_sb_single(), * because get_sb_single()/sget() find and use the super-block from * the most recent mount of devpts. But that recent mount may be a * 'newinstance' mount and get_sb_single() would pick the newinstance * super-block instead of the initial super-block. */ static int devpts_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt) { int error; struct pts_mount_opts opts; struct super_block *s; error = parse_mount_options(data, PARSE_MOUNT, &opts); if (error) return error; if (opts.newinstance) s = sget(fs_type, NULL, set_anon_super, NULL); else s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL); if (IS_ERR(s)) return PTR_ERR(s); if (!s->s_root) { s->s_flags = flags; error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0); if (error) goto out_undo_sget; s->s_flags |= MS_ACTIVE; } simple_set_mnt(mnt, s); memcpy(&(DEVPTS_SB(s))->mount_opts, &opts, sizeof(opts)); error = mknod_ptmx(s); if (error) goto out_dput; return 0; out_dput: dput(s->s_root); /* undo dget() in simple_set_mnt() */ out_undo_sget: deactivate_locked_super(s); return error; }