]> git.hungrycats.org Git - linux/commitdiff
[PATCH] dynamic pty allocation
authorAndrew Morton <akpm@osdl.org>
Sun, 22 Feb 2004 15:01:12 +0000 (07:01 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Sun, 22 Feb 2004 15:01:12 +0000 (07:01 -0800)
From: "H. Peter Anvin" <hpa@transmeta.com>

Remove the limit of 2048 pty's - allocate them on demand up to the 12:20
dev_t limit: a million.

drivers/char/Kconfig
drivers/char/pty.c
drivers/char/tty_io.c
fs/Kconfig
fs/devpts/Makefile
fs/devpts/inode.c
include/linux/devpts_fs.h
include/linux/sysctl.h
include/linux/tty.h
include/linux/tty_driver.h
kernel/sysctl.c

index 0f97c45d7df04df168dadfef270d947da8b576ca..a6b4b1378f0298099fee7062e18585ea3006266d 100644 (file)
@@ -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/<number>. 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.
+         All modern Linux systems use the Unix98 ptys.  Say Y unless
+         you're on an embedded system and want to conserve memory.
 
-         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 <file:Documentation/Changes> pertaining to
-         pseudo terminals. It's safe to say N.
+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 UNIX98_PTY_COUNT
-       int "Maximum number of Unix98 PTYs in use (0-2048)"
-       depends on UNIX98_PTYS
+
+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"
index 135a4b6463a19ccd991c79f03544222de6331b0e..4abc4d95b26df54cc63c4cde957aac2a7e2e7fd5 100644 (file)
 #include <linux/mm.h>
 #include <linux/init.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/sysctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 #include <linux/devpts_fs.h>
 
+#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_struct *tty, int * arg)
        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_struct *tty, struct file *file,
        }
        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_struct *tty, struct file *file,
                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 */
index 33a9c5cb4ecd266d7ce9b92dd44c9d06f80b4ab8..c3e87291247ea8caab12e7c6f484e7fceb2b44af 100644 (file)
@@ -124,7 +124,7 @@ struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table     */
 
 #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 *driver, int idx,
        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 *driver, int idx,
        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 *driver, int idx,
                *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 *driver, int idx,
                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 *driver, int idx,
                        *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 *driver, int idx,
                /*
                 * 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 *driver, int idx,
         * 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_struct *tty, int idx)
 {
        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_struct *tty, int idx)
                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 * filp)
                                  "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 * filp)
 #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_driver *driver)
         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_driver *driver)
                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);
index 5959280da570cdd846f45bdce0434b937bbffb1f..65202333d1797c6a103130b361d36d325604de9c 100644 (file)
@@ -797,8 +797,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,
          <http://www.kernel.org/pub/linux/utils/kernel/hotplug/>.
@@ -831,32 +830,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/<number>. 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 <file:Documentation/Changes> 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
index 1d5a2697b9698fd9522cfce1ae8b902e9640e21f..5eb7a942a0b7d2f97051811cc7a0bbf7f5cf7c57 100644 (file)
@@ -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
index dacf0e2d9f0adbe204481ae9bc743139382dca34..1d49ef4af3b6e5d6b70d353e7a8241eca4af0a25 100644 (file)
@@ -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 <linux/sched.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/tty.h>
+#include <linux/devpts_fs.h>
 #include "xattr.h"
 
 #define DEVPTS_SUPER_MAGIC 0x1cd1
@@ -126,7 +128,7 @@ static struct file_system_type devpts_fs_type = {
 
 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_file_inode_operations = {
        .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 device)
        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)
index 4def3512b35582dfcc87c0be491119ab5493d46f..734f7ea9e835d9286ec9d586fc3b4615d18e2413 100644 (file)
@@ -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
 #ifndef _LINUX_DEVPTS_FS_H
 #define _LINUX_DEVPTS_FS_H 1
 
-#ifdef CONFIG_DEVPTS_FS
+#include <linux/errno.h>
 
-void devpts_pty_new(int, dev_t);       /* mknod in devpts */
-void devpts_pty_kill(int);             /* unlink */
+#if CONFIG_UNIX98_PTYS
 
-#else
+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 */
 
-static inline void devpts_pty_new(int line, dev_t device)
-{
-}
+#else
 
-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 */
index f800e292d8a1b511b84cef4e54e2d70047d406af..6819132d40d4caeb1b59804aa5b72d9c564d6633 100644 (file)
@@ -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 */
 };
 
 
@@ -192,6 +193,13 @@ enum
        RANDOM_UUID=6
 };
 
+/* /proc/sys/kernel/pty */
+enum
+{
+       PTY_MAX=1,
+       PTY_NR=2
+};
+
 /* /proc/sys/bus/isa */
 enum
 {
index 0626d1b321aa79d273154955a63ea18e8f563995..ca1f1ccf6c49d655bfd062d299fc6ba308eba91d 100644 (file)
 
 
 /*
- * 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:
index 63051af4d8ac76f37e4a03bf8d38f85db0e4d826..f0b98e5a5473c8d4000f5023c32bfb1e6445baba 100644 (file)
@@ -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_driver *driver, struct tty_operations *op);
  * 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
index d74fa91d8dd77e7e9d88192d4e89465fcbd24670..a94662452734fb037a2c7f198e02f57e03f6deef 100644 (file)
@@ -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",