Commit 562123b5 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] dynamic pty allocation

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.
parent d6ca3890
......@@ -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"
......
......@@ -25,16 +25,21 @@
#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 */
......@@ -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 @@ static int tty_open(struct inode * inode, struct file * filp)
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);
......
......@@ -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
......
......@@ -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
......@@ -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)
......
......@@ -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 <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 */
......@@ -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
{
......
......@@ -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:
......
......@@ -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
......
......@@ -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",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment