diff options
author | Kay Sievers <kay@vrfy.org> | 2012-04-09 15:37:43 +0200 |
---|---|---|
committer | Kay Sievers <kay@vrfy.org> | 2012-04-09 15:37:43 +0200 |
commit | e405cbaeb791321de4fd649e915af2449d339f32 (patch) | |
tree | cca4971304c87ad61c602606088b54cb46380c1c | |
parent | 3391b400d44b1892f184d8c3393fbd112c44c090 (diff) | |
download | patches-e405cbaeb791321de4fd649e915af2449d339f32.tar.gz |
add devpts patch
-rw-r--r-- | devpts.patch | 447 | ||||
-rw-r--r-- | series | 2 |
2 files changed, 449 insertions, 0 deletions
diff --git a/devpts.patch b/devpts.patch new file mode 100644 index 0000000..cca51dc --- /dev/null +++ b/devpts.patch @@ -0,0 +1,447 @@ +Subject: devpts: properly integrate with /dev/ptmx + +The following patch is just to clean up the confusion about userspace +and the unfortunate idea of legacy vs. non-legacy mount options. It is +nowhere ready to merge, but it should make is pretty clear, that +userspace should be left alone here, and it's a job for the kernel only. + +# ls -l /dev +crw------- 1 root root 10, 1 Apr 9 14:21 psaux +lrwxrwxrwx 1 root root 8 Apr 9 14:20 ptmx -> pts/ptmx +drwxr-xr-x 2 root root 0 Apr 9 14:21 pts +crw-rw-rw- 1 root root 1, 8 Apr 9 14:21 random + +# ls -l /dev/pts +total 0 +crw--w---- 1 root tty 136, 0 Apr 9 14:22 0 +crw--w---- 1 kay tty 136, 1 Apr 9 14:22 1 +crw-rw-rw- 1 root tty 5, 2 Apr 9 14:22 ptmx + +--- + drivers/base/devtmpfs.c | 60 ++++++++++++++++++++++++- + drivers/tty/Kconfig | 11 ---- + drivers/tty/pty.c | 3 - + fs/devpts/inode.c | 112 +++++++----------------------------------------- + include/linux/device.h | 2 + 5 files changed, 76 insertions(+), 112 deletions(-) + +--- a/drivers/base/devtmpfs.c ++++ b/drivers/base/devtmpfs.c +@@ -40,6 +40,7 @@ static struct req { + struct completion done; + int err; + const char *name; ++ const char *target; + umode_t mode; /* 0 => delete */ + struct device *dev; + } *requests; +@@ -84,7 +85,7 @@ int devtmpfs_create_node(struct device * + if (!thread) + return 0; + +- req.mode = 0; ++ memset(&req, 0, sizeof(struct req)); + req.name = device_get_devnode(dev, &req.mode, &tmp); + if (!req.name) + return -ENOMEM; +@@ -113,6 +114,31 @@ int devtmpfs_create_node(struct device * + return req.err; + } + ++int devtmpfs_create_link(const char *name, const char *target) ++{ ++ struct req req; ++ ++ if (!thread) ++ return 0; ++ ++ memset(&req, 0, sizeof(struct req)); ++ req.mode = 0666; ++ req.name = name; ++ req.target = target; ++ ++ init_completion(&req.done); ++ ++ spin_lock(&req_lock); ++ req.next = requests; ++ requests = &req; ++ spin_unlock(&req_lock); ++ ++ wake_up_process(thread); ++ wait_for_completion(&req.done); ++ ++ return req.err; ++} ++ + int devtmpfs_delete_node(struct device *dev) + { + const char *tmp = NULL; +@@ -121,11 +147,11 @@ int devtmpfs_delete_node(struct device * + if (!thread) + return 0; + ++ memset(&req, 0, sizeof(struct req)); + req.name = device_get_devnode(dev, NULL, &tmp); + if (!req.name) + return -ENOMEM; + +- req.mode = 0; + req.dev = dev; + + init_completion(&req.done); +@@ -225,6 +251,28 @@ static int handle_create(const char *nod + return err; + } + ++static int handle_create_link(const char *name, const char *target) ++{ ++ struct dentry *dentry; ++ struct path path; ++ int err; ++ ++ dentry = kern_path_create(AT_FDCWD, name, &path, 0); ++ if (dentry == ERR_PTR(-ENOENT)) { ++ create_path(name); ++ dentry = kern_path_create(AT_FDCWD, name, &path, 0); ++ } ++ if (IS_ERR(dentry)) ++ return PTR_ERR(dentry); ++ ++ err = vfs_symlink(path.dentry->d_inode, dentry, target); ++ dput(dentry); ++ ++ mutex_unlock(&path.dentry->d_inode->i_mutex); ++ path_put(&path); ++ return err; ++} ++ + static int dev_rmdir(const char *name) + { + struct nameidata nd; +@@ -378,8 +426,11 @@ int devtmpfs_mount(const char *mntdir) + + static DECLARE_COMPLETION(setup_done); + +-static int handle(const char *name, umode_t mode, struct device *dev) ++static int handle(const char *name, umode_t mode, ++ struct device *dev, const char *target) + { ++ if (target) ++ return handle_create_link(name, target); + if (mode) + return handle_create(name, mode, dev); + else +@@ -407,7 +458,8 @@ static int devtmpfsd(void *p) + spin_unlock(&req_lock); + while (req) { + struct req *next = req->next; +- req->err = handle(req->name, req->mode, req->dev); ++ req->err = handle(req->name, req->mode, ++ req->dev, req->target); + complete(&req->done); + req = next; + } +--- a/drivers/tty/Kconfig ++++ b/drivers/tty/Kconfig +@@ -109,17 +109,6 @@ config UNIX98_PTYS + All modern Linux systems use the Unix98 ptys. Say Y unless + you're on an embedded system and want to conserve memory. + +-config DEVPTS_MULTIPLE_INSTANCES +- bool "Support multiple instances of devpts" +- depends on UNIX98_PTYS +- default n +- ---help--- +- Enable support for multiple instances of devpts filesystem. +- If you want to have isolated PTY namespaces (eg: in containers), +- say Y here. Otherwise, say N. If enabled, each mount of devpts +- filesystem with the '-o newinstance' option will create an +- independent PTY namespace. +- + config LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y +--- a/drivers/tty/pty.c ++++ b/drivers/tty/pty.c +@@ -706,7 +706,7 @@ static void __init unix98_pty_init(void) + if (tty_register_driver(pts_driver)) + panic("Couldn't register Unix98 pts driver"); + +- /* Now create the /dev/ptmx special device */ ++ /* Hook up the ptmx cdev which lives inside the devpts filesystem */ + tty_default_fops(&ptmx_fops); + ptmx_fops.open = ptmx_open; + +@@ -714,7 +714,6 @@ static void __init unix98_pty_init(void) + if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || + register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) + panic("Couldn't register /dev/ptmx driver\n"); +- device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + } + + #else +--- a/fs/devpts/inode.c ++++ b/fs/devpts/inode.c +@@ -26,15 +26,9 @@ + #include <linux/fsnotify.h> + #include <linux/seq_file.h> + +-#define DEVPTS_DEFAULT_MODE 0600 +-/* +- * ptmx is a new node in /dev/pts and will be unused in legacy (single- +- * instance) mode. To prevent surprises in user space, set permissions of +- * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful +- * permissions. +- */ +-#define DEVPTS_DEFAULT_PTMX_MODE 0000 +-#define PTMX_MINOR 2 ++#define DEVPTS_DEFAULT_MODE 0600 ++#define DEVPTS_DEFAULT_PTMX_MODE 0666 ++#define PTMX_MINOR 2 + + /* + * sysctl support for setting limits on the number of Unix98 ptys allocated. +@@ -102,24 +96,19 @@ struct pts_mount_opts { + gid_t gid; + umode_t mode; + umode_t ptmxmode; +- int newinstance; + int max; + }; + + enum { +- Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max, +- Opt_err ++ Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_max, Opt_err + }; + + static const match_table_t tokens = { + {Opt_uid, "uid=%u"}, + {Opt_gid, "gid=%u"}, + {Opt_mode, "mode=%o"}, +-#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES + {Opt_ptmxmode, "ptmxmode=%o"}, +- {Opt_newinstance, "newinstance"}, + {Opt_max, "max=%d"}, +-#endif + {Opt_err, NULL} + }; + +@@ -136,10 +125,8 @@ static inline struct pts_fs_info *DEVPTS + + static inline struct super_block *pts_sb_from_inode(struct inode *inode) + { +-#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES + if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) + return inode->i_sb; +-#endif + return devpts_mnt->mnt_sb; + } + +@@ -149,9 +136,7 @@ static inline struct super_block *pts_sb + /* + * parse_mount_options(): + * Set @opts to mount options specified in @data. If an option is not +- * specified in @data, set it to its default value. The exception is +- * 'newinstance' option which can only be set/cleared on a mount (i.e. +- * cannot be changed during remount). ++ * specified in @data, set it to its default value.\ + * + * Note: @data may be NULL (in which case all options are set to default). + */ +@@ -167,10 +152,6 @@ static int parse_mount_options(char *dat + opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; + opts->max = NR_UNIX98_PTY_MAX; + +- /* newinstance makes sense only on initial mount */ +- if (op == PARSE_MOUNT) +- opts->newinstance = 0; +- + while ((p = strsep(&data, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + int token; +@@ -198,24 +179,17 @@ static int parse_mount_options(char *dat + return -EINVAL; + opts->mode = option & S_IALLUGO; + break; +-#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES + case Opt_ptmxmode: + if (match_octal(&args[0], &option)) + return -EINVAL; + opts->ptmxmode = option & S_IALLUGO; + break; +- case Opt_newinstance: +- /* newinstance makes sense only on initial mount */ +- if (op == PARSE_MOUNT) +- opts->newinstance = 1; +- break; + case Opt_max: + if (match_int(&args[0], &option) || + option < 0 || option > NR_UNIX98_PTY_MAX) + return -EINVAL; + opts->max = option; + break; +-#endif + default: + printk(KERN_ERR "devpts: called with bogus options\n"); + return -EINVAL; +@@ -225,7 +199,6 @@ static int parse_mount_options(char *dat + return 0; + } + +-#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES + static int mknod_ptmx(struct super_block *sb) + { + int mode; +@@ -260,6 +233,8 @@ static int mknod_ptmx(struct super_block + goto out; + } + ++ if (opts->setgid) ++ inode->i_gid = opts->gid; + inode->i_ino = 2; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + +@@ -283,12 +258,6 @@ static void update_ptmx_mode(struct pts_ + inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode; + } + } +-#else +-static inline void update_ptmx_mode(struct pts_fs_info *fsi) +-{ +- return; +-} +-#endif + + static int devpts_remount(struct super_block *sb, int *flags, char *data) + { +@@ -319,11 +288,9 @@ static int devpts_show_options(struct se + if (opts->setgid) + seq_printf(seq, ",gid=%u", opts->gid); + seq_printf(seq, ",mode=%03o", opts->mode); +-#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES + seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); + if (opts->max < NR_UNIX98_PTY_MAX) + seq_printf(seq, ",max=%d", opts->max); +-#endif + + return 0; + } +@@ -384,43 +351,8 @@ fail: + return -ENOMEM; + } + +-#ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES +-static int compare_init_pts_sb(struct super_block *s, void *p) +-{ +- if (devpts_mnt) +- return devpts_mnt->mnt_sb == s; +- return 0; +-} +- +-/* +- * 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 flags, const char *dev_name, void *data) + { + int error; + struct pts_mount_opts opts; +@@ -430,10 +362,7 @@ static struct dentry *devpts_mount(struc + if (error) + return ERR_PTR(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); ++ s = sget(fs_type, NULL, set_anon_super, NULL); + + if (IS_ERR(s)) + return ERR_CAST(s); +@@ -459,18 +388,6 @@ out_undo_sget: + return ERR_PTR(error); + } + +-#else +-/* +- * This supports only the legacy single-instance semantics (no +- * multiple-instance semantics) +- */ +-static struct dentry *devpts_mount(struct file_system_type *fs_type, int flags, +- const char *dev_name, void *data) +-{ +- return mount_single(fs_type, flags, data, devpts_fill_super); +-} +-#endif +- + static void devpts_kill_sb(struct super_block *sb) + { + struct pts_fs_info *fsi = DEVPTS_SB(sb); +@@ -502,8 +419,7 @@ retry: + return -ENOMEM; + + mutex_lock(&allocated_ptys_lock); +- if (pty_count >= pty_limit - +- (fsi->mount_opts.newinstance ? pty_reserve : 0)) { ++ if (pty_count >= pty_limit - pty_reserve) { + mutex_unlock(&allocated_ptys_lock); + return -ENOSPC; + } +@@ -629,9 +545,15 @@ void devpts_pty_kill(struct tty_struct * + + static int __init init_devpts_fs(void) + { +- int err = register_filesystem(&devpts_fs_type); ++ int err; + struct ctl_table_header *table; + ++ err = devtmpfs_create_link("ptmx", "pts/ptmx"); ++ if (err) ++ return err; ++ ++ err = register_filesystem(&devpts_fs_type); ++ + if (!err) { + table = register_sysctl_table(pty_root_table); + devpts_mnt = kern_mount(&devpts_fs_type); +--- a/include/linux/device.h ++++ b/include/linux/device.h +@@ -858,10 +858,12 @@ extern void put_device(struct device *de + extern void wait_for_device_probe(void); + + #ifdef CONFIG_DEVTMPFS ++extern int devtmpfs_create_link(const char *name, const char *target); + extern int devtmpfs_create_node(struct device *dev); + extern int devtmpfs_delete_node(struct device *dev); + extern int devtmpfs_mount(const char *mntdir); + #else ++static int devtmpfs_create_link(const char *name, const char *target) { return 0; } + static inline int devtmpfs_create_node(struct device *dev) { return 0; } + static inline int devtmpfs_delete_node(struct device *dev) { return 0; } + static inline int devtmpfs_mount(const char *mountpoint) { return 0; } @@ -2,3 +2,5 @@ printk-records.patch printk-devkmsg.patch printk-dev_printk.patch kern-cont.patch +devpts.patch + |