summaryrefslogtreecommitdiff
path: root/drivers/tty/pty.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/pty.c')
-rw-r--r--drivers/tty/pty.c118
1 files changed, 68 insertions, 50 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index 7c4447a5c0f4..e72ee629cead 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -47,10 +47,13 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
set_bit(TTY_IO_ERROR, &tty->flags);
wake_up_interruptible(&tty->read_wait);
wake_up_interruptible(&tty->write_wait);
+ spin_lock_irq(&tty->ctrl_lock);
tty->packet = 0;
+ spin_unlock_irq(&tty->ctrl_lock);
/* Review - krefs on tty_link ?? */
if (!tty->link)
return;
+ tty_flush_to_ldisc(tty->link);
set_bit(TTY_OTHER_CLOSED, &tty->link->flags);
wake_up_interruptible(&tty->link->read_wait);
wake_up_interruptible(&tty->link->write_wait);
@@ -64,9 +67,7 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
mutex_unlock(&devpts_mutex);
}
#endif
- tty_unlock(tty);
tty_vhangup(tty->link);
- tty_lock(tty);
}
}
@@ -87,19 +88,6 @@ static void pty_unthrottle(struct tty_struct *tty)
}
/**
- * pty_space - report space left for writing
- * @to: tty we are writing into
- *
- * Limit the buffer space used by ptys to 8k.
- */
-
-static int pty_space(struct tty_struct *to)
-{
- int n = tty_buffer_space_avail(to->port);
- return min(n, 8192);
-}
-
-/**
* pty_write - write to a pty
* @tty: the tty we write from
* @buf: kernel buffer of data
@@ -140,7 +128,7 @@ static int pty_write_room(struct tty_struct *tty)
{
if (tty->stopped)
return 0;
- return pty_space(tty->link);
+ return tty_buffer_space_avail(tty->link->port);
}
/**
@@ -178,21 +166,21 @@ static int pty_get_lock(struct tty_struct *tty, int __user *arg)
/* Set the packet mode on a pty */
static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
{
- unsigned long flags;
int pktmode;
if (get_user(pktmode, arg))
return -EFAULT;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
+ spin_lock_irq(&tty->ctrl_lock);
if (pktmode) {
if (!tty->packet) {
- tty->packet = 1;
tty->link->ctrl_status = 0;
+ smp_mb();
+ tty->packet = 1;
}
} else
tty->packet = 0;
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_unlock_irq(&tty->ctrl_lock);
return 0;
}
@@ -207,15 +195,15 @@ static int pty_get_pktmode(struct tty_struct *tty, int __user *arg)
/* Send a signal to the slave */
static int pty_signal(struct tty_struct *tty, int sig)
{
- unsigned long flags;
struct pid *pgrp;
- if (tty->link) {
- spin_lock_irqsave(&tty->link->ctrl_lock, flags);
- pgrp = get_pid(tty->link->pgrp);
- spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
+ if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP)
+ return -EINVAL;
- kill_pgrp(pgrp, sig, 1);
+ if (tty->link) {
+ pgrp = tty_get_pgrp(tty->link);
+ if (pgrp)
+ kill_pgrp(pgrp, sig, 1);
put_pid(pgrp);
}
return 0;
@@ -224,16 +212,21 @@ static int pty_signal(struct tty_struct *tty, int sig)
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
- unsigned long flags;
+ struct tty_ldisc *ld;
if (!to)
return;
- /* tty_buffer_flush(to); FIXME */
+
+ ld = tty_ldisc_ref(to);
+ tty_buffer_flush(to, ld);
+ if (ld)
+ tty_ldisc_deref(ld);
+
if (to->packet) {
- spin_lock_irqsave(&tty->ctrl_lock, flags);
+ spin_lock_irq(&tty->ctrl_lock);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&to->read_wait);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ spin_unlock_irq(&tty->ctrl_lock);
}
}
@@ -262,6 +255,32 @@ out:
static void pty_set_termios(struct tty_struct *tty,
struct ktermios *old_termios)
{
+ /* See if packet mode change of state. */
+ if (tty->link && tty->link->packet) {
+ int extproc = (old_termios->c_lflag & EXTPROC) |
+ (tty->termios.c_lflag & EXTPROC);
+ int old_flow = ((old_termios->c_iflag & IXON) &&
+ (old_termios->c_cc[VSTOP] == '\023') &&
+ (old_termios->c_cc[VSTART] == '\021'));
+ int new_flow = (I_IXON(tty) &&
+ STOP_CHAR(tty) == '\023' &&
+ START_CHAR(tty) == '\021');
+ if ((old_flow != new_flow) || extproc) {
+ spin_lock_irq(&tty->ctrl_lock);
+ if (old_flow != new_flow) {
+ tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
+ if (new_flow)
+ tty->ctrl_status |= TIOCPKT_DOSTOP;
+ else
+ tty->ctrl_status |= TIOCPKT_NOSTOP;
+ }
+ if (extproc)
+ tty->ctrl_status |= TIOCPKT_IOCTL;
+ spin_unlock_irq(&tty->ctrl_lock);
+ wake_up_interruptible(&tty->link->read_wait);
+ }
+ }
+
tty->termios.c_cflag &= ~(CSIZE | PARENB);
tty->termios.c_cflag |= (CS8 | CREAD);
}
@@ -278,7 +297,6 @@ static void pty_set_termios(struct tty_struct *tty,
static int pty_resize(struct tty_struct *tty, struct winsize *ws)
{
struct pid *pgrp, *rpgrp;
- unsigned long flags;
struct tty_struct *pty = tty->link;
/* For a PTY we need to lock the tty side */
@@ -286,17 +304,9 @@ static int pty_resize(struct tty_struct *tty, struct winsize *ws)
if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done;
- /* Get the PID values and reference them so we can
- avoid holding the tty ctrl lock while sending signals.
- We need to lock these individually however. */
-
- spin_lock_irqsave(&tty->ctrl_lock, flags);
- pgrp = get_pid(tty->pgrp);
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-
- spin_lock_irqsave(&pty->ctrl_lock, flags);
- rpgrp = get_pid(pty->pgrp);
- spin_unlock_irqrestore(&pty->ctrl_lock, flags);
+ /* Signal the foreground process group of both ptys */
+ pgrp = tty_get_pgrp(tty);
+ rpgrp = tty_get_pgrp(pty);
if (pgrp)
kill_pgrp(pgrp, SIGWINCH, 1);
@@ -327,26 +337,26 @@ static void pty_start(struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->link && tty->link->packet) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status &= ~TIOCPKT_STOP;
tty->ctrl_status |= TIOCPKT_START;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
}
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
static void pty_stop(struct tty_struct *tty)
{
unsigned long flags;
- spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->link && tty->link->packet) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status &= ~TIOCPKT_START;
tty->ctrl_status |= TIOCPKT_STOP;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
wake_up_interruptible_poll(&tty->link->read_wait, POLLIN);
}
- spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
/**
@@ -368,6 +378,10 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
int idx = tty->index;
int retval = -ENOMEM;
+ /* Opening the slave first has always returned -EIO */
+ if (driver->subtype != PTY_TYPE_MASTER)
+ return -EIO;
+
ports[0] = kmalloc(sizeof **ports, GFP_KERNEL);
ports[1] = kmalloc(sizeof **ports, GFP_KERNEL);
if (!ports[0] || !ports[1])
@@ -380,6 +394,9 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
if (!o_tty)
goto err_put_module;
+ tty_set_lock_subclass(o_tty);
+ lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE);
+
if (legacy) {
/* We always use new tty termios data so we can do this
the easy way .. */
@@ -404,19 +421,22 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
* Everything allocated ... set up the o_tty structure.
*/
tty_driver_kref_get(driver->other);
- if (driver->subtype == PTY_TYPE_MASTER)
- o_tty->count++;
/* Establish the links in both directions */
tty->link = o_tty;
o_tty->link = tty;
tty_port_init(ports[0]);
tty_port_init(ports[1]);
+ tty_buffer_set_limit(ports[0], 8192);
+ tty_buffer_set_limit(ports[1], 8192);
o_tty->port = ports[0];
tty->port = ports[1];
o_tty->port->itty = o_tty;
+ tty_buffer_set_lock_subclass(o_tty->port);
+
tty_driver_kref_get(driver);
tty->count++;
+ o_tty->count++;
return 0;
err_free_termios:
if (legacy)
@@ -489,7 +509,6 @@ static const struct tty_operations master_pty_ops_bsd = {
.flush_buffer = pty_flush_buffer,
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
- .set_termios = pty_set_termios,
.ioctl = pty_bsd_ioctl,
.cleanup = pty_cleanup,
.resize = pty_resize,
@@ -666,7 +685,6 @@ static const struct tty_operations ptm_unix98_ops = {
.flush_buffer = pty_flush_buffer,
.chars_in_buffer = pty_chars_in_buffer,
.unthrottle = pty_unthrottle,
- .set_termios = pty_set_termios,
.ioctl = pty_unix98_ioctl,
.resize = pty_resize,
.shutdown = pty_unix98_shutdown,