From: "H. Peter Anvin" Remove the limit of 2048 pty's - allocate them on demand up to the 12:20 dev_t limit: a million. --- 25-akpm/drivers/char/Kconfig | 53 +++++++------ 25-akpm/drivers/char/pty.c | 69 ++++++++++++++--- 25-akpm/drivers/char/tty_io.c | 149 +++++++++++++++++++++++++------------ 25-akpm/fs/Kconfig | 28 ------ 25-akpm/fs/devpts/Makefile | 4 25-akpm/fs/devpts/inode.c | 36 +++++++- 25-akpm/include/linux/devpts_fs.h | 23 ++--- 25-akpm/include/linux/sysctl.h | 8 + 25-akpm/include/linux/tty.h | 24 ----- 25-akpm/include/linux/tty_driver.h | 11 +- 25-akpm/kernel/sysctl.c | 11 ++ 11 files changed, 271 insertions(+), 145 deletions(-) diff -puN drivers/char/Kconfig~dynamic-pty-allocation drivers/char/Kconfig --- 25/drivers/char/Kconfig~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/drivers/char/Kconfig Fri Feb 13 18:04:19 2004 @@ -445,7 +445,8 @@ config A2232 source "drivers/serial/Kconfig" config UNIX98_PTYS - bool "Unix98 PTY support" + bool "Unix98 PTY support" if EMBEDDED + default y ---help--- A pseudo terminal (PTY) is a software device consisting of two halves: a master and a slave. The slave device behaves identical to @@ -463,28 +464,38 @@ config UNIX98_PTYS terminal slave can be accessed as /dev/pts/. What was traditionally /dev/ttyp2 will then be /dev/pts/2, for example. - The entries in /dev/pts/ are created on the fly by a virtual - file system; therefore, if you say Y here you should say Y to - "/dev/pts file system for Unix98 PTYs" as well. - - If you want to say Y here, you need to have the C library glibc 2.1 - or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*"). - Read the instructions in pertaining to - pseudo terminals. It's safe to say N. - -config UNIX98_PTY_COUNT - int "Maximum number of Unix98 PTYs in use (0-2048)" - depends on 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 LEGACY_PTYS + bool "Legacy (BSD) PTY support" + default y + ---help--- + A pseudo terminal (PTY) is a software device consisting of two + halves: a master and a slave. The slave device behaves identical to + a physical terminal; the master device is used by a process to + read data from and write data to the slave, thereby emulating a + terminal. Typical programs for the master side are telnet servers + and xterms. + + Linux has traditionally used the BSD-like names /dev/ptyxx + for masters and /dev/ttyxx for slaves of pseudo + terminals. This scheme has a number of problems, including + security. This option enables these legacy devices; on most + systems, it is safe to say N. + + +config LEGACY_PTY_COUNT + int "Maximum number of legacy PTY in use" + depends on LEGACY_PTYS default "256" - help - The maximum number of Unix98 PTYs that can be used at any one time. - The default is 256, and should be enough for desktop systems. Server - machines which support incoming telnet/rlogin/ssh connections and/or - serve several X terminals may want to increase this: every incoming - connection and every xterm uses up one PTY. + ---help--- + The maximum number of legacy PTYs that can be used at any one time. + The default is 256, and should be more than enough. Embedded + systems may want to reduce this to save memory. - When not in use, each additional set of 256 PTYs occupy - approximately 8 KB of kernel memory on 32-bit architectures. + When not in use, each legacy PTY occupies 12 bytes on 32-bit + architectures and 24 bytes on 64-bit architectures. config PRINTER tristate "Parallel printer support" diff -puN drivers/char/pty.c~dynamic-pty-allocation drivers/char/pty.c --- 25/drivers/char/pty.c~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/drivers/char/pty.c Fri Feb 13 18:04:19 2004 @@ -25,16 +25,21 @@ #include #include #include +#include #include #include #include #include +#if defined(CONFIG_LEGACY_PTYS) || defined(CONFIG_UNIX98_PTYS) + +#ifdef CONFIG_LEGACY_PTYS static struct tty_driver *pty_driver, *pty_slave_driver; +#endif -#ifdef CONFIG_UNIX98_PTYS /* These are global because they are accessed in tty_io.c */ +#ifdef CONFIG_UNIX98_PTYS struct tty_driver *ptm_driver; struct tty_driver *pts_driver; #endif @@ -226,8 +231,9 @@ static int pty_set_lock(struct tty_struc return 0; } +#ifdef CONFIG_LEGACY_PTYS static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { if (!tty) { printk("pty_ioctl called with NULL tty!\n"); @@ -239,6 +245,7 @@ static int pty_bsd_ioctl(struct tty_stru } return -ENOIOCTLCMD; } +#endif #ifdef CONFIG_UNIX98_PTYS static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, @@ -249,11 +256,13 @@ static int pty_unix98_ioctl(struct tty_s return -EIO; } switch(cmd) { + case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ + return pty_set_lock(tty, (int *)arg); case TIOCGPTN: /* Get PT Number */ return pty_get_device_number(tty, (unsigned int *)arg); } - return pty_bsd_ioctl(tty,file,cmd,arg); + return -ENOIOCTLCMD; } #endif @@ -313,8 +322,41 @@ static struct tty_operations pty_ops = { .set_termios = pty_set_termios, }; +/* sysctl support for setting limits on the number of Unix98 ptys allocated. + Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */ +#ifdef CONFIG_UNIX98_PTYS +int pty_limit = NR_UNIX98_PTY_DEFAULT; +static int pty_limit_min = 0; +static int pty_limit_max = NR_UNIX98_PTY_MAX; + +ctl_table pty_table[] = { + { + .ctl_name = PTY_MAX, + .procname = "max", + .maxlen = sizeof(int), + .mode = 0644, + .data = &pty_limit, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &pty_limit_min, + .extra2 = &pty_limit_max, + }, { + .ctl_name = PTY_NR, + .procname = "nr", + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, { + .ctl_name = 0 + } +}; +#endif + +/* Initialization */ + static int __init pty_init(void) { +#ifdef CONFIG_LEGACY_PTYS /* Traditional BSD devices */ pty_driver = alloc_tty_driver(NR_PTYS); @@ -363,15 +405,15 @@ static int __init pty_init(void) if (tty_register_driver(pty_slave_driver)) panic("Couldn't register pty slave driver"); +#endif /* CONFIG_LEGACY_PTYS */ - /* Unix98 devices */ #ifdef CONFIG_UNIX98_PTYS + /* Unix98 devices */ devfs_mk_dir("pts"); - printk("pty: %d Unix98 ptys configured\n", UNIX98_NR_MAJORS*NR_PTYS); - ptm_driver = alloc_tty_driver(UNIX98_NR_MAJORS * NR_PTYS); + ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); if (!ptm_driver) panic("Couldn't allocate Unix98 ptm driver"); - pts_driver = alloc_tty_driver(UNIX98_NR_MAJORS * NR_PTYS); + pts_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX); if (!pts_driver) panic("Couldn't allocate Unix98 pts driver"); @@ -388,7 +430,7 @@ static int __init pty_init(void) ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; ptm_driver->init_termios.c_lflag = 0; ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_NO_DEVFS; + TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; tty_set_operations(ptm_driver, &pty_ops); ptm_driver->ioctl = pty_unix98_ioctl; @@ -402,8 +444,8 @@ static int __init pty_init(void) pts_driver->subtype = PTY_TYPE_SLAVE; pts_driver->init_termios = tty_std_termios; pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | + TTY_DRIVER_NO_DEVFS | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; tty_set_operations(pts_driver, &pty_ops); @@ -411,7 +453,12 @@ static int __init pty_init(void) panic("Couldn't register Unix98 ptm driver"); if (tty_register_driver(pts_driver)) panic("Couldn't register Unix98 pts driver"); -#endif + + pty_table[1].data = &ptm_driver->refcount; +#endif /* CONFIG_UNIX98_PTYS */ + return 0; } module_init(pty_init); + +#endif /* CONFIG_LEGACY_PTYS || CONFIG_UNIX98_PTYS */ diff -puN drivers/char/tty_io.c~dynamic-pty-allocation drivers/char/tty_io.c --- 25/drivers/char/tty_io.c~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/drivers/char/tty_io.c Fri Feb 13 18:04:19 2004 @@ -124,7 +124,7 @@ struct tty_ldisc ldiscs[NR_LDISCS]; /* l #ifdef CONFIG_UNIX98_PTYS extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ -extern struct tty_driver *pts_driver; /* Unix98 pty slaves; for /dev/ptmx */ +extern int pty_limit; /* Config limit on Unix98 ptys */ #endif extern void disable_early_printk(void); @@ -799,7 +799,13 @@ static int init_dev(struct tty_driver *d down_tty_sem(idx); /* check whether we're reopening an existing tty */ - tty = driver->ttys[idx]; + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tty = devpts_get_tty(idx); + if (tty && driver->subtype == PTY_TYPE_MASTER) + tty = tty->link; + } else { + tty = driver->ttys[idx]; + } if (tty) goto fast_track; /* @@ -827,7 +833,14 @@ static int init_dev(struct tty_driver *d tty->index = idx; tty_line_name(driver, idx, tty->name); - tp_loc = &driver->termios[idx]; + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + tp_loc = &tty->termios; + ltp_loc = &tty->termios_locked; + } else { + tp_loc = &driver->termios[idx]; + ltp_loc = &driver->termios_locked[idx]; + } + if (!*tp_loc) { tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); @@ -836,7 +849,6 @@ static int init_dev(struct tty_driver *d *tp = driver->init_termios; } - ltp_loc = &driver->termios_locked[idx]; if (!*ltp_loc) { ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); @@ -854,7 +866,14 @@ static int init_dev(struct tty_driver *d o_tty->index = idx; tty_line_name(driver->other, idx, o_tty->name); - o_tp_loc = &driver->other->termios[idx]; + if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { + o_tp_loc = &o_tty->termios; + o_ltp_loc = &o_tty->termios_locked; + } else { + o_tp_loc = &driver->other->termios[idx]; + o_ltp_loc = &driver->other->termios_locked[idx]; + } + if (!*o_tp_loc) { o_tp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); @@ -863,7 +882,6 @@ static int init_dev(struct tty_driver *d *o_tp = driver->other->init_termios; } - o_ltp_loc = &driver->other->termios_locked[idx]; if (!*o_ltp_loc) { o_ltp = (struct termios *) kmalloc(sizeof(struct termios), GFP_KERNEL); @@ -875,7 +893,9 @@ static int init_dev(struct tty_driver *d /* * Everything allocated ... set up the o_tty structure. */ - driver->other->ttys[idx] = o_tty; + if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) { + driver->other->ttys[idx] = o_tty; + } if (!*o_tp_loc) *o_tp_loc = o_tp; if (!*o_ltp_loc) @@ -896,7 +916,9 @@ static int init_dev(struct tty_driver *d * Failures after this point use release_mem to clean up, so * there's no need to null out the local pointers. */ - driver->ttys[idx] = tty; + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + driver->ttys[idx] = tty; + } if (!*tp_loc) *tp_loc = tp; @@ -994,12 +1016,20 @@ static void release_mem(struct tty_struc { struct tty_struct *o_tty; struct termios *tp; + int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; if ((o_tty = tty->link) != NULL) { - o_tty->driver->ttys[idx] = NULL; + if (!devpts) + o_tty->driver->ttys[idx] = NULL; if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - tp = o_tty->driver->termios[idx]; - o_tty->driver->termios[idx] = NULL; + tp = o_tty->termios; + if (!devpts) + o_tty->driver->termios[idx] = NULL; + kfree(tp); + + tp = o_tty->termios_locked; + if (!devpts) + o_tty->driver->termios_locked[idx] = NULL; kfree(tp); } o_tty->magic = 0; @@ -1010,12 +1040,20 @@ static void release_mem(struct tty_struc free_tty_struct(o_tty); } - tty->driver->ttys[idx] = NULL; + if (!devpts) + tty->driver->ttys[idx] = NULL; if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - tp = tty->driver->termios[idx]; - tty->driver->termios[idx] = NULL; + tp = tty->termios; + if (!devpts) + tty->driver->termios[idx] = NULL; + kfree(tp); + + tp = tty->termios_locked; + if (!devpts) + tty->driver->termios_locked[idx] = NULL; kfree(tp); } + tty->magic = 0; tty->driver->refcount--; file_list_lock(); @@ -1059,22 +1097,24 @@ static void release_dev(struct file * fi "free (%s)\n", tty->name); return; } - if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " - "for (%s)\n", idx, tty->name); - return; - } - if (tty->termios != tty->driver->termios[idx]) { - printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " - "for (%s)\n", - idx, tty->name); - return; - } - if (tty->termios_locked != tty->driver->termios_locked[idx]) { - printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " - "termios_locked for (%s)\n", - idx, tty->name); - return; + if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + if (tty != tty->driver->ttys[idx]) { + printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " + "for (%s)\n", idx, tty->name); + return; + } + if (tty->termios != tty->driver->termios[idx]) { + printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " + "for (%s)\n", + idx, tty->name); + return; + } + if (tty->termios_locked != tty->driver->termios_locked[idx]) { + printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " + "termios_locked for (%s)\n", + idx, tty->name); + return; + } } #endif @@ -1084,7 +1124,8 @@ static void release_dev(struct file * fi #endif #ifdef TTY_PARANOIA_CHECK - if (tty->driver->other) { + if (tty->driver->other && + !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (o_tty != tty->driver->other->ttys[idx]) { printk(KERN_DEBUG "release_dev: other->table[%d] " "not o_tty for (%s)\n", @@ -1328,23 +1369,29 @@ retry_open: return -ENODEV; } - if (device == MKDEV(TTYAUX_MAJOR,2)) { #ifdef CONFIG_UNIX98_PTYS + if (device == MKDEV(TTYAUX_MAJOR,2)) { /* find a device that is not in use. */ + static int next_ptmx_dev = 0; retval = -1; driver = ptm_driver; - for (index = 0; index < driver->num ; index++) + while (driver->refcount < pty_limit) { + index = next_ptmx_dev; + next_ptmx_dev = (next_ptmx_dev+1) % driver->num; if (!init_dev(driver, index, &tty)) goto ptmx_found; /* ok! */ + } return -EIO; /* no free ptys */ ptmx_found: set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - devpts_pty_new(index, MKDEV(pts_driver->major, pts_driver->minor_start) + index); + if (devpts_pty_new(tty->link)) { + /* BADNESS - need to destroy both ptm and pts! */ + return -ENOMEM; + } noctty = 1; -#else - return -ENODEV; -#endif /* CONFIG_UNIX_98_PTYS */ - } else { + } else +#endif + { driver = get_tty_driver(device, &index); if (!driver) return -ENODEV; @@ -2190,15 +2237,17 @@ int tty_register_driver(struct tty_drive int i; dev_t dev; char *s; - void **p; + void **p = NULL; if (driver->flags & TTY_DRIVER_INSTALLED) return 0; - p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); - if (!p) - return -ENOMEM; - memset(p, 0, driver->num * 3 * sizeof(void *)); + if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); + if (!p) + return -ENOMEM; + memset(p, 0, driver->num * 3 * sizeof(void *)); + } if (!driver->major) { error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, @@ -2217,9 +2266,15 @@ int tty_register_driver(struct tty_drive return error; } - driver->ttys = (struct tty_struct **)p; - driver->termios = (struct termios **)(p + driver->num); - driver->termios_locked = (struct termios **)(p + driver->num * 2); + if (p) { + driver->ttys = (struct tty_struct **)p; + driver->termios = (struct termios **)(p + driver->num); + driver->termios_locked = (struct termios **)(p + driver->num * 2); + } else { + driver->ttys = NULL; + driver->termios = NULL; + driver->termios_locked = NULL; + } driver->cdev.kobj.parent = &tty_kobj; strcpy(driver->cdev.kobj.name, driver->name); @@ -2388,7 +2443,7 @@ static int __init tty_init(void) devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif - + #ifdef CONFIG_VT strcpy(vc0_cdev.kobj.name, "dev.vc0"); cdev_init(&vc0_cdev, &console_fops); diff -puN fs/devpts/inode.c~dynamic-pty-allocation fs/devpts/inode.c --- 25/fs/devpts/inode.c~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/fs/devpts/inode.c Fri Feb 13 18:04:19 2004 @@ -2,7 +2,7 @@ * * linux/fs/devpts/inode.c * - * Copyright 1998 H. Peter Anvin -- All Rights Reserved + * Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "xattr.h" #define DEVPTS_SUPER_MAGIC 0x1cd1 @@ -126,7 +128,7 @@ static struct file_system_type devpts_fs static struct dentry *get_node(int num) { - char s[10]; + char s[12]; struct dentry *root = devpts_root; down(&root->d_inode->i_sem); return lookup_one_len(s, root, sprintf(s, "%d", num)); @@ -139,12 +141,21 @@ static struct inode_operations devpts_fi .removexattr = devpts_removexattr, }; -void devpts_pty_new(int number, dev_t device) +int devpts_pty_new(struct tty_struct *tty) { + int number = tty->index; + struct tty_driver *driver = tty->driver; + dev_t device = MKDEV(driver->major, driver->minor_start+number); struct dentry *dentry; struct inode *inode = new_inode(devpts_mnt->mnt_sb); + + /* We're supposed to be given the slave end of a pty */ + BUG_ON(driver->type != TTY_DRIVER_TYPE_PTY); + BUG_ON(driver->subtype != PTY_TYPE_SLAVE); + if (!inode) - return; + return -ENOMEM; + inode->i_ino = number+2; inode->i_blksize = 1024; inode->i_uid = config.setuid ? config.uid : current->fsuid; @@ -152,11 +163,28 @@ void devpts_pty_new(int number, dev_t de inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|config.mode, device); inode->i_op = &devpts_file_inode_operations; + inode->u.generic_ip = tty; dentry = get_node(number); if (!IS_ERR(dentry) && !dentry->d_inode) d_instantiate(dentry, inode); + up(&devpts_root->d_inode->i_sem); + + return 0; +} + +struct tty_struct *devpts_get_tty(int number) +{ + struct dentry *dentry = get_node(number); + struct tty_struct *tty; + + tty = (IS_ERR(dentry) || !dentry->d_inode) ? NULL : + dentry->d_inode->u.generic_ip; + + up(&devpts_root->d_inode->i_sem); + + return tty; } void devpts_pty_kill(int number) diff -puN fs/devpts/Makefile~dynamic-pty-allocation fs/devpts/Makefile --- 25/fs/devpts/Makefile~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/fs/devpts/Makefile Fri Feb 13 18:04:19 2004 @@ -2,8 +2,8 @@ # Makefile for the Linux /dev/pts virtual filesystem. # -obj-$(CONFIG_DEVPTS_FS) += devpts.o +obj-$(CONFIG_UNIX98_PTYS) += devpts.o -devpts-y := inode.o +devpts-$(CONFIG_UNIX98_PTYS) := inode.o devpts-$(CONFIG_DEVPTS_FS_XATTR) += xattr.o devpts-$(CONFIG_DEVPTS_FS_SECURITY) += xattr_security.o diff -puN fs/Kconfig~dynamic-pty-allocation fs/Kconfig --- 25/fs/Kconfig~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/fs/Kconfig Fri Feb 13 18:04:19 2004 @@ -821,8 +821,7 @@ config DEVFS_FS the file README there. Note that devfs no longer manages /dev/pts! If you are using UNIX98 - ptys, you will also need to enable (and mount) the /dev/pts - filesystem (CONFIG_DEVPTS_FS). + ptys, you will also need to mount the /dev/pts filesystem (devpts). Note that devfs has been obsoleted by udev, . @@ -855,32 +854,9 @@ config DEVFS_DEBUG If unsure, say N. -config DEVPTS_FS -# It compiles as a module for testing only. It should not be used -# as a module in general. If we make this "tristate", a bunch of people -# who don't know what they are doing turn it on and complain when it -# breaks. - bool "/dev/pts file system for Unix98 PTYs" - depends on UNIX98_PTYS - ---help--- - You should say Y here if you said Y to "Unix98 PTY support" above. - You'll then get a virtual file system which can be mounted on - /dev/pts with "mount -t devpts". This, together with the pseudo - terminal master multiplexer /dev/ptmx, is used for pseudo terminal - support as described in The Open Group's Unix98 standard: in order - to acquire a pseudo terminal, a process opens /dev/ptmx; the number - of the pseudo terminal is then made available to the process and the - pseudo terminal slave can be accessed as /dev/pts/. What was - traditionally /dev/ttyp2 will then be /dev/pts/2, for example. - - The GNU C library glibc 2.1 contains the requisite support for this - mode of operation; you also need client programs that use the Unix98 - API. Please read for more information - about the Unix98 pty devices. - config DEVPTS_FS_XATTR bool "/dev/pts Extended Attributes" - depends on DEVPTS_FS + depends on UNIX98_PTYS help Extended attributes are name:value pairs associated with inodes by the kernel or by users (see the attr(5) manual page, or visit diff -puN include/linux/devpts_fs.h~dynamic-pty-allocation include/linux/devpts_fs.h --- 25/include/linux/devpts_fs.h~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/include/linux/devpts_fs.h Fri Feb 13 18:04:19 2004 @@ -2,7 +2,7 @@ * * linux/include/linux/devpts_fs.h * - * Copyright 1998 H. Peter Anvin -- All Rights Reserved + * Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved * * This file is part of the Linux kernel and is made available under * the terms of the GNU General Public License, version 2, or at your @@ -13,21 +13,22 @@ #ifndef _LINUX_DEVPTS_FS_H #define _LINUX_DEVPTS_FS_H 1 -#ifdef CONFIG_DEVPTS_FS +#include -void devpts_pty_new(int, dev_t); /* mknod in devpts */ -void devpts_pty_kill(int); /* unlink */ +#if CONFIG_UNIX98_PTYS + +int devpts_pty_new(struct tty_struct *); /* mknod in devpts */ +struct tty_struct *devpts_get_tty(int); /* get tty structure */ +void devpts_pty_kill(int); /* unlink */ #else -static inline void devpts_pty_new(int line, dev_t device) -{ -} - -static inline void devpts_pty_kill(int line) -{ -} +/* Dummy stubs in the no-pty case */ +static inline int devpts_pty_new(struct tty_struct *) { return -EINVAL; } +static inline struct tty_struct *devpts_get_tty(int) { return NULL; } +static inline void devpts_pty_kill(int) { } #endif + #endif /* _LINUX_DEVPTS_FS_H */ diff -puN include/linux/sysctl.h~dynamic-pty-allocation include/linux/sysctl.h --- 25/include/linux/sysctl.h~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/include/linux/sysctl.h Fri Feb 13 18:04:19 2004 @@ -129,6 +129,7 @@ enum KERN_HPPA_UNALIGNED=59, /* int: hppa unaligned-trap enable */ KERN_PRINTK_RATELIMIT=60, /* int: tune printk ratelimiting */ KERN_PRINTK_RATELIMIT_BURST=61, /* int: tune printk ratelimiting */ + KERN_PTY=62, /* dir: pty driver */ }; @@ -194,6 +195,13 @@ enum RANDOM_UUID=6 }; +/* /proc/sys/kernel/pty */ +enum +{ + PTY_MAX=1, + PTY_NR=2 +}; + /* /proc/sys/bus/isa */ enum { diff -puN include/linux/tty_driver.h~dynamic-pty-allocation include/linux/tty_driver.h --- 25/include/linux/tty_driver.h~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/include/linux/tty_driver.h Fri Feb 13 18:04:19 2004 @@ -160,9 +160,10 @@ struct tty_driver { const char *devfs_name; const char *name; int name_base; /* offset of printed name */ - short major; /* major device number */ - short minor_start; /* start of minor device number*/ - short num; /* number of devices */ + int major; /* major device number */ + int minor_start; /* start of minor device number */ + int minor_num; /* number of *possible* devices */ + int num; /* number of devices allocated */ short type; /* type of tty driver */ short subtype; /* subtype of tty driver */ struct termios init_termios; /* Initial termios */ @@ -244,11 +245,15 @@ void tty_set_operations(struct tty_drive * TTY_DRIVER_NO_DEVFS --- if set, do not create devfs entries. This * is only used by tty_register_driver(). * + * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead + * use dynamic memory keyed through the devpts filesystem. This + * is only applicable to the pty driver. */ #define TTY_DRIVER_INSTALLED 0x0001 #define TTY_DRIVER_RESET_TERMIOS 0x0002 #define TTY_DRIVER_REAL_RAW 0x0004 #define TTY_DRIVER_NO_DEVFS 0x0008 +#define TTY_DRIVER_DEVPTS_MEM 0x0010 /* tty driver types */ #define TTY_DRIVER_TYPE_SYSTEM 0x0001 diff -puN include/linux/tty.h~dynamic-pty-allocation include/linux/tty.h --- 25/include/linux/tty.h~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/include/linux/tty.h Fri Feb 13 18:04:19 2004 @@ -28,29 +28,13 @@ /* - * Note: don't mess with NR_PTYS until you understand the tty minor - * number allocation game... * (Note: the *_driver.minor_start values 1, 64, 128, 192 are * hardcoded at present.) */ -#define NR_PTYS 256 /* ptys/major */ -#define NR_LDISCS 16 - -/* - * Unix98 PTY's can be defined as any multiple of NR_PTYS up to - * UNIX98_PTY_MAJOR_COUNT; this section defines what we need from the - * config options - */ -#ifdef CONFIG_UNIX98_PTYS -# define UNIX98_NR_MAJORS ((CONFIG_UNIX98_PTY_COUNT+NR_PTYS-1)/NR_PTYS) -# if UNIX98_NR_MAJORS <= 0 -# undef CONFIG_UNIX98_PTYS -# elif UNIX98_NR_MAJORS > UNIX98_PTY_MAJOR_COUNT -# error Too many Unix98 ptys defined -# undef UNIX98_NR_MAJORS -# define UNIX98_NR_MAJORS UNIX98_PTY_MAJOR_COUNT -# endif -#endif +#define NR_PTYS CONFIG_LEGACY_PTY_COUNT /* Number of legacy ptys */ +#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ +#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ +#define NR_LDISCS 16 /* * These are set up by the setup-routine at boot-time: diff -puN kernel/sysctl.c~dynamic-pty-allocation kernel/sysctl.c --- 25/kernel/sysctl.c~dynamic-pty-allocation Fri Feb 13 18:04:19 2004 +++ 25-akpm/kernel/sysctl.c Fri Feb 13 18:04:19 2004 @@ -133,6 +133,9 @@ static ctl_table fs_table[]; static ctl_table debug_table[]; static ctl_table dev_table[]; extern ctl_table random_table[]; +#ifdef CONFIG_UNIX98_PTYS +extern ctl_table pty_table[]; +#endif /* /proc declarations: */ @@ -518,6 +521,14 @@ static ctl_table kern_table[] = { .mode = 0555, .child = random_table, }, +#ifdef CONFIG_UNIX98_PTYS + { + .ctl_name = KERN_PTY, + .procname = "pty", + .mode = 0555, + .child = pty_table, + }, +#endif { .ctl_name = KERN_OVERFLOWUID, .procname = "overflowuid", _