diff options
Diffstat (limited to 'drivers/tty/pty.c')
| -rw-r--r-- | drivers/tty/pty.c | 124 |
1 files changed, 86 insertions, 38 deletions
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 4219f040adb..25c9bc78372 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -38,16 +38,18 @@ static void pty_close(struct tty_struct *tty, struct file *filp) if (tty->driver->subtype == PTY_TYPE_MASTER) WARN_ON(tty->count > 1); else { + if (test_bit(TTY_IO_ERROR, &tty->flags)) + return; if (tty->count > 2) return; } + set_bit(TTY_IO_ERROR, &tty->flags); wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); tty->packet = 0; /* Review - krefs on tty_link ?? */ if (!tty->link) return; - tty->link->packet = 0; set_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->write_wait); @@ -55,9 +57,10 @@ static void pty_close(struct tty_struct *tty, struct file *filp) set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS if (tty->driver == ptm_driver) { - mutex_lock(&devpts_mutex); - devpts_pty_kill(tty->link->driver_data); - mutex_unlock(&devpts_mutex); + mutex_lock(&devpts_mutex); + if (tty->link->driver_data) + devpts_pty_kill(tty->link->driver_data); + mutex_unlock(&devpts_mutex); } #endif tty_unlock(tty); @@ -86,17 +89,13 @@ static void pty_unthrottle(struct tty_struct *tty) * pty_space - report space left for writing * @to: tty we are writing into * - * The tty buffers allow 64K but we sneak a peak and clip at 8K this - * allows a lot of overspill room for echo and other fun messes to - * be handled properly + * Limit the buffer space used by ptys to 8k. */ static int pty_space(struct tty_struct *to) { - int n = 8192 - to->port->buf.memory_used; - if (n < 0) - return 0; - return n; + int n = tty_buffer_space_avail(to->port); + return min(n, 8192); } /** @@ -120,12 +119,10 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) if (c > 0) { /* Stuff the data into the input queue of the other end */ - c = tty_insert_flip_string(to, buf, c); + c = tty_insert_flip_string(to->port, buf, c); /* And shovel */ - if (c) { - tty_flip_buffer_push(to); - tty_wakeup(tty); - } + if (c) + tty_flip_buffer_push(to->port); } return c; } @@ -171,6 +168,41 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg) return 0; } +static int pty_get_lock(struct tty_struct *tty, int __user *arg) +{ + int locked = test_bit(TTY_PTY_LOCK, &tty->flags); + return put_user(locked, 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); + if (pktmode) { + if (!tty->packet) { + tty->packet = 1; + tty->link->ctrl_status = 0; + } + } else + tty->packet = 0; + spin_unlock_irqrestore(&tty->ctrl_lock, flags); + + return 0; +} + +/* Get the packet mode of a pty */ +static int pty_get_pktmode(struct tty_struct *tty, int __user *arg) +{ + int pktmode = tty->packet; + return put_user(pktmode, arg); +} + /* Send a signal to the slave */ static int pty_signal(struct tty_struct *tty, int sig) { @@ -206,24 +238,24 @@ static void pty_flush_buffer(struct tty_struct *tty) static int pty_open(struct tty_struct *tty, struct file *filp) { - int retval = -ENODEV; - if (!tty || !tty->link) - goto out; + return -ENODEV; - retval = -EIO; if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) goto out; if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) goto out; - if (tty->link->count != 1) + if (tty->driver->subtype == PTY_TYPE_SLAVE && tty->link->count != 1) goto out; + clear_bit(TTY_IO_ERROR, &tty->flags); clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); set_bit(TTY_THROTTLED, &tty->flags); - retval = 0; + return 0; + out: - return retval; + set_bit(TTY_IO_ERROR, &tty->flags); + return -EIO; } static void pty_set_termios(struct tty_struct *tty, @@ -242,14 +274,14 @@ static void pty_set_termios(struct tty_struct *tty, * peform a terminal resize correctly */ -int pty_resize(struct tty_struct *tty, struct winsize *ws) +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 */ - mutex_lock(&tty->termios_mutex); + mutex_lock(&tty->winsize_mutex); if (!memcmp(ws, &tty->winsize, sizeof(*ws))) goto done; @@ -276,7 +308,7 @@ int pty_resize(struct tty_struct *tty, struct winsize *ws) tty->winsize = *ws; pty->winsize = *ws; /* Never used so will go away soon */ done: - mutex_unlock(&tty->termios_mutex); + mutex_unlock(&tty->winsize_mutex); return 0; } @@ -364,16 +396,9 @@ err: return retval; } -/* this is called once with whichever end is closed last */ -static void pty_unix98_shutdown(struct tty_struct *tty) -{ - devpts_kill_index(tty->driver_data, tty->index); -} - static void pty_cleanup(struct tty_struct *tty) { - tty->port->itty = NULL; - kfree(tty->port); + tty_port_put(tty->port); } /* Traditional BSD devices */ @@ -398,8 +423,16 @@ static int pty_bsd_ioctl(struct tty_struct *tty, switch (cmd) { case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ return pty_set_lock(tty, (int __user *) arg); + case TIOCGPTLCK: /* Get PT Lock status */ + return pty_get_lock(tty, (int __user *)arg); + case TIOCPKT: /* Set PT packet mode */ + return pty_set_pktmode(tty, (int __user *)arg); + case TIOCGPKT: /* Get PT packet mode */ + return pty_get_pktmode(tty, (int __user *)arg); case TIOCSIG: /* Send signal to other side of pty */ return pty_signal(tty, (int) arg); + case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */ + return -EINVAL; } return -ENOIOCTLCMD; } @@ -512,6 +545,12 @@ static int pty_unix98_ioctl(struct tty_struct *tty, switch (cmd) { case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ return pty_set_lock(tty, (int __user *)arg); + case TIOCGPTLCK: /* Get PT Lock status */ + return pty_get_lock(tty, (int __user *)arg); + case TIOCPKT: /* Set PT packet mode */ + return pty_set_pktmode(tty, (int __user *)arg); + case TIOCGPKT: /* Get PT packet mode */ + return pty_get_pktmode(tty, (int __user *)arg); case TIOCGPTN: /* Get PT Number */ return put_user(tty->index, (unsigned int __user *)arg); case TIOCSIG: /* Send signal to other side of pty */ @@ -572,6 +611,12 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) { } +/* this is called once with whichever end is closed last */ +static void pty_unix98_shutdown(struct tty_struct *tty) +{ + devpts_kill_index(tty->driver_data, tty->index); +} + static const struct tty_operations ptm_unix98_ops = { .lookup = ptm_unix98_lookup, .install = pty_unix98_install, @@ -614,7 +659,7 @@ static const struct tty_operations pty_unix98_ops = { * Allocate a unix98 pty master device from the ptmx driver. * * Locking: tty_mutex protects the init_dev work. tty->count should - * protect the rest. + * protect the rest. * allocated_ptys_lock handles the list of free pty numbers */ @@ -627,6 +672,9 @@ static int ptmx_open(struct inode *inode, struct file *filp) nonseekable_open(inode, filp); + /* We refuse fsnotify events on ptmx, since it's a shared resource */ + filp->f_mode |= FMODE_NONOTIFY; + retval = tty_alloc_file(filp); if (retval) return retval; @@ -655,6 +703,7 @@ static int ptmx_open(struct inode *inode, struct file *filp) mutex_unlock(&tty_mutex); set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + tty->driver_data = inode; tty_add_file(tty, filp); @@ -665,14 +714,13 @@ static int ptmx_open(struct inode *inode, struct file *filp) retval = PTR_ERR(slave_inode); goto err_release; } + tty->link->driver_data = slave_inode; retval = ptm_driver->ops->open(tty, filp); if (retval) goto err_release; tty_unlock(tty); - tty->driver_data = inode; - tty->link->driver_data = slave_inode; return 0; err_release: tty_unlock(tty); @@ -748,7 +796,7 @@ static void __init unix98_pty_init(void) cdev_init(&ptmx_cdev, &ptmx_fops); if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) - panic("Couldn't register /dev/ptmx driver\n"); + panic("Couldn't register /dev/ptmx driver"); device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); } |
