From 593a27c4b212e2afdf772a1f8dcb894e91bda0fa Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 5 Jan 2012 13:04:21 +0400 Subject: tty: cleanup prohibition of direct opening for unix98 pty master cleanup hack added in v2.6.27-3203-g15582d3 comment from that patch: : pty: If the administrator creates a device for a ptmx slave we should not error : : The open path for ptmx slaves is via the ptmx device. Opening them any : other way is not allowed. Vegard Nossum found that previously this was not : the case and mknod foo c 128 42; cat foo would produce nasty diagnostics : : Signed-off-by: Alan Cox : Signed-off-by: Linus Torvalds devpts_get_tty() returns non-null only for inodes on devpts, but there is no inodes for master-devices, /dev/ptmx (/dev/pts/ptmx) is the only way to open them. Thus we can completely forbid lookup for master-devices and eliminate that hack in tty_init_dev() because tty_open() will get EIO from tty_driver_lookup_tty(). Signed-off-by: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux/tty.h') diff --git a/include/linux/tty.h b/include/linux/tty.h index 5dbb3cb05a82..d3ebd765b548 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -480,8 +480,7 @@ extern void free_tty_struct(struct tty_struct *tty); extern void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx); extern void deinitialize_tty_struct(struct tty_struct *tty); -extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, - int first_ok); +extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); extern int tty_release(struct inode *inode, struct file *filp); extern int tty_init_termios(struct tty_struct *tty); -- cgit From e9aba5158a80098447ff207a452a3418ae7ee386 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Thu, 5 Jan 2012 13:06:11 +0400 Subject: tty: rework pty count limiting After adding devpts multiple-insrances sysctl kernel.pty.max limit pty count for each devpts instance independently, while kernel.pty.nr shows total pty count. This patch restores sysctl kernel.pty.max as global limit (4096 by default), adds pty reseve for main devpts (mounted without "newinstance" argument), and new sysctl to tune it: kernel.pty.reserve (1024 by default) Also it adds devpts mount option "max=%d" to limit pty count for each devpts instance independently. (by default NR_UNIX98_PTY_MAX == 2^20) Thus devpts instances in containers cannot eat up all available pty even if we didn't set any limits, while with "max" argument we can adjust limits more precisely. Plus, now open("/dev/ptmx") return -ENOSPC in case lack of pty indexes, this is more informative than -EIO. Signed-off-by: Konstantin Khlebnikov Signed-off-by: Greg Kroah-Hartman --- fs/devpts/inode.c | 34 ++++++++++++++++++++++++++++++---- include/linux/tty.h | 1 + 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'include/linux/tty.h') diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index c2c7317d5687..1c6f908e38ca 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -41,8 +41,9 @@ * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */ static int pty_limit = NR_UNIX98_PTY_DEFAULT; +static int pty_reserve = NR_UNIX98_PTY_RESERVE; static int pty_limit_min; -static int pty_limit_max = NR_UNIX98_PTY_MAX; +static int pty_limit_max = INT_MAX; static int pty_count; static struct ctl_table pty_table[] = { @@ -54,6 +55,14 @@ static struct ctl_table pty_table[] = { .proc_handler = proc_dointvec_minmax, .extra1 = &pty_limit_min, .extra2 = &pty_limit_max, + }, { + .procname = "reserve", + .maxlen = sizeof(int), + .mode = 0644, + .data = &pty_reserve, + .proc_handler = proc_dointvec_minmax, + .extra1 = &pty_limit_min, + .extra2 = &pty_limit_max, }, { .procname = "nr", .maxlen = sizeof(int), @@ -94,10 +103,11 @@ struct pts_mount_opts { umode_t mode; umode_t ptmxmode; int newinstance; + int max; }; enum { - Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, + Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max, Opt_err }; @@ -108,6 +118,7 @@ static const match_table_t tokens = { #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES {Opt_ptmxmode, "ptmxmode=%o"}, {Opt_newinstance, "newinstance"}, + {Opt_max, "max=%d"}, #endif {Opt_err, NULL} }; @@ -154,6 +165,7 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) opts->gid = 0; opts->mode = DEVPTS_DEFAULT_MODE; opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; + opts->max = NR_UNIX98_PTY_MAX; /* newinstance makes sense only on initial mount */ if (op == PARSE_MOUNT) @@ -197,6 +209,12 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) 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"); @@ -303,6 +321,8 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root) 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; @@ -483,6 +503,12 @@ retry: return -ENOMEM; mutex_lock(&allocated_ptys_lock); + if (pty_count >= pty_limit - + (fsi->mount_opts.newinstance ? pty_reserve : 0)) { + mutex_unlock(&allocated_ptys_lock); + return -ENOSPC; + } + ida_ret = ida_get_new(&fsi->allocated_ptys, &index); if (ida_ret < 0) { mutex_unlock(&allocated_ptys_lock); @@ -491,10 +517,10 @@ retry: return -EIO; } - if (index >= pty_limit) { + if (index >= fsi->mount_opts.max) { ida_remove(&fsi->allocated_ptys, index); mutex_unlock(&allocated_ptys_lock); - return -EIO; + return -ENOSPC; } pty_count++; mutex_unlock(&allocated_ptys_lock); diff --git a/include/linux/tty.h b/include/linux/tty.h index d3ebd765b548..d40774188203 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -52,6 +52,7 @@ * hardcoded at present.) */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ +#define NR_UNIX98_PTY_RESERVE 1024 /* Default reserve for main devpts */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ /* -- cgit From 66d450e84ec656ec4b774c41cd8d46b3e48d51df Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 30 Jan 2012 21:14:28 +0100 Subject: TTY: provide tty_standard_install helper There are currently many cut&paste copies of what tty_driver_install_tty does when custom ->install method is not provided. Let's get rid of the copies and create a helper with this setup code. Signed-off-by: Jiri Slaby Cc: Havard Skinnemoen Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 30 +++++++++++++++--------------- include/linux/tty.h | 2 ++ 2 files changed, 17 insertions(+), 15 deletions(-) (limited to 'include/linux/tty.h') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index fbcc14063804..44736f9e61d7 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1271,6 +1271,19 @@ int tty_init_termios(struct tty_struct *tty) } EXPORT_SYMBOL_GPL(tty_init_termios); +int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) +{ + int ret = tty_init_termios(tty); + if (ret) + return ret; + + tty_driver_kref_get(driver); + tty->count++; + driver->ttys[tty->index] = tty; + return 0; +} +EXPORT_SYMBOL_GPL(tty_standard_install); + /** * tty_driver_install_tty() - install a tty entry in the driver * @driver: the driver for the tty @@ -1286,21 +1299,8 @@ EXPORT_SYMBOL_GPL(tty_init_termios); static int tty_driver_install_tty(struct tty_driver *driver, struct tty_struct *tty) { - int idx = tty->index; - int ret; - - if (driver->ops->install) { - ret = driver->ops->install(driver, tty); - return ret; - } - - if (tty_init_termios(tty) == 0) { - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[idx] = tty; - return 0; - } - return -ENOMEM; + return driver->ops->install ? driver->ops->install(driver, tty) : + tty_standard_install(driver, tty); } /** diff --git a/include/linux/tty.h b/include/linux/tty.h index d40774188203..a91ff403b3bf 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -484,6 +484,8 @@ extern void deinitialize_tty_struct(struct tty_struct *tty); extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); extern int tty_release(struct inode *inode, struct file *filp); extern int tty_init_termios(struct tty_struct *tty); +extern int tty_standard_install(struct tty_driver *driver, + struct tty_struct *tty); extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty); extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty); -- cgit