diff options
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r-- | drivers/char/tty_io.c | 115 |
1 files changed, 64 insertions, 51 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 507441ac6ed..5ee9081a560 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -149,6 +149,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, #else #define tty_compat_ioctl NULL #endif +static int __tty_fasync(int fd, struct file *filp, int on); static int tty_fasync(int fd, struct file *filp, int on); static void release_tty(struct tty_struct *tty, int idx); static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); @@ -483,7 +484,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup); * remains intact. * * Locking: - * BKL + * BTM * redirect lock for undoing redirection * file list lock for manipulating list of ttys * tty_ldisc_lock from called functions @@ -513,8 +514,11 @@ static void do_tty_hangup(struct work_struct *work) } spin_unlock(&redirect_lock); - /* inuse_filps is protected by the single kernel lock */ - lock_kernel(); + /* inuse_filps is protected by the single tty lock, + this really needs to change if we want to flush the + workqueue with the lock held */ + tty_lock_nested(); /* called with BTM held from pty_close and + others */ check_tty_count(tty, "do_tty_hangup"); file_list_lock(); @@ -525,7 +529,7 @@ static void do_tty_hangup(struct work_struct *work) if (filp->f_op->write != tty_write) continue; closecount++; - tty_fasync(-1, filp, 0); /* can't block */ + __tty_fasync(-1, filp, 0); /* can't block */ filp->f_op = &hung_up_tty_fops; } file_list_unlock(); @@ -594,7 +598,7 @@ static void do_tty_hangup(struct work_struct *work) */ set_bit(TTY_HUPPED, &tty->flags); tty_ldisc_enable(tty); - unlock_kernel(); + tty_unlock(); if (f) fput(f); } @@ -696,7 +700,8 @@ static void session_clear_tty(struct pid *session) * exiting; it is 0 if called by the ioctl TIOCNOTTY. * * Locking: - * BKL is taken for hysterical raisins + * BTM is taken for hysterical raisins, and held when + * called from no_tty(). * tty_mutex is taken to protect tty * ->siglock is taken to protect ->signal/->sighand * tasklist_lock is taken to walk process list for sessions @@ -714,10 +719,10 @@ void disassociate_ctty(int on_exit) tty = get_current_tty(); if (tty) { tty_pgrp = get_pid(tty->pgrp); - lock_kernel(); + tty_lock_nested(); /* see above */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); - unlock_kernel(); + tty_unlock(); tty_kref_put(tty); } else if (on_exit) { struct pid *old_pgrp; @@ -774,9 +779,9 @@ void disassociate_ctty(int on_exit) void no_tty(void) { struct task_struct *tsk = current; - lock_kernel(); + tty_lock(); disassociate_ctty(0); - unlock_kernel(); + tty_unlock(); proc_clear_tty(tsk); } @@ -1013,19 +1018,19 @@ out: * We don't put it into the syslog queue right now maybe in the future if * really needed. * - * We must still hold the BKL and test the CLOSING flag for the moment. + * We must still hold the BTM and test the CLOSING flag for the moment. */ void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { mutex_lock(&tty->atomic_write_lock); - lock_kernel(); + tty_lock(); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { - unlock_kernel(); + tty_unlock(); tty->ops->write(tty, msg, strlen(msg)); } else - unlock_kernel(); + tty_unlock(); tty_write_unlock(tty); } return; @@ -1208,18 +1213,18 @@ static int tty_driver_install_tty(struct tty_driver *driver, int ret; if (driver->ops->install) { - lock_kernel(); + tty_lock_nested(); /* already called with BTM held */ ret = driver->ops->install(driver, tty); - unlock_kernel(); + tty_unlock(); return ret; } if (tty_init_termios(tty) == 0) { - lock_kernel(); + tty_lock_nested(); tty_driver_kref_get(driver); tty->count++; driver->ttys[idx] = tty; - unlock_kernel(); + tty_unlock(); return 0; } return -ENOMEM; @@ -1312,14 +1317,15 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, struct tty_struct *tty; int retval; - lock_kernel(); + tty_lock_nested(); /* always called with tty lock held already */ + /* Check if pty master is being opened multiple times */ if (driver->subtype == PTY_TYPE_MASTER && (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) { - unlock_kernel(); + tty_unlock(); return ERR_PTR(-EIO); } - unlock_kernel(); + tty_unlock(); /* * First time open is complex, especially for PTY devices. @@ -1363,9 +1369,9 @@ release_mem_out: if (printk_ratelimit()) printk(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); - lock_kernel(); + tty_lock_nested(); release_tty(tty, idx); - unlock_kernel(); + tty_unlock(); return ERR_PTR(retval); } @@ -1512,10 +1518,10 @@ int tty_release(struct inode *inode, struct file *filp) if (tty_paranoia_check(tty, inode, "tty_release_dev")) return 0; - lock_kernel(); + tty_lock(); check_tty_count(tty, "tty_release_dev"); - tty_fasync(-1, filp, 0); + __tty_fasync(-1, filp, 0); idx = tty->index; pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -1527,18 +1533,18 @@ int tty_release(struct inode *inode, struct file *filp) if (idx < 0 || idx >= tty->driver->num) { printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " "free (%s)\n", tty->name); - unlock_kernel(); + tty_unlock(); return 0; } if (!devpts) { if (tty != tty->driver->ttys[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " "for (%s)\n", idx, tty->name); return 0; } if (tty->termios != tty->driver->termios[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, tty->name); @@ -1556,21 +1562,21 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->driver->other && !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (o_tty != tty->driver->other->ttys[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: other->table[%d] " "not o_tty for (%s)\n", idx, tty->name); return 0 ; } if (o_tty->termios != tty->driver->other->termios[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: other->termios[%d] " "not o_termios for (%s)\n", idx, tty->name); return 0; } if (o_tty->link != tty) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n"); return 0; } @@ -1579,7 +1585,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - unlock_kernel(); + tty_unlock(); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1602,7 +1608,7 @@ int tty_release(struct inode *inode, struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); - lock_kernel(); + tty_lock(); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1633,7 +1639,7 @@ int tty_release(struct inode *inode, struct file *filp) printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " "active!\n", tty_name(tty, buf)); - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); schedule(); } @@ -1698,7 +1704,7 @@ int tty_release(struct inode *inode, struct file *filp) /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) { - unlock_kernel(); + tty_unlock(); return 0; } @@ -1718,7 +1724,7 @@ int tty_release(struct inode *inode, struct file *filp) /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - unlock_kernel(); + tty_unlock(); return 0; } @@ -1760,12 +1766,12 @@ retry_open: retval = 0; mutex_lock(&tty_mutex); - lock_kernel(); + tty_lock(); if (device == MKDEV(TTYAUX_MAJOR, 0)) { tty = get_current_tty(); if (!tty) { - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return -ENXIO; } @@ -1797,14 +1803,14 @@ retry_open: goto got_driver; } } - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return -ENODEV; } driver = get_tty_driver(device, &index); if (!driver) { - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return -ENODEV; } @@ -1814,7 +1820,7 @@ got_driver: tty = tty_driver_lookup_tty(driver, inode, index); if (IS_ERR(tty)) { - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return PTR_ERR(tty); } @@ -1830,7 +1836,7 @@ got_driver: mutex_unlock(&tty_mutex); tty_driver_kref_put(driver); if (IS_ERR(tty)) { - unlock_kernel(); + tty_unlock(); return PTR_ERR(tty); } @@ -1862,11 +1868,11 @@ got_driver: #endif tty_release(inode, filp); if (retval != -ERESTARTSYS) { - unlock_kernel(); + tty_unlock(); return retval; } if (signal_pending(current)) { - unlock_kernel(); + tty_unlock(); return retval; } schedule(); @@ -1875,14 +1881,14 @@ got_driver: */ if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; - unlock_kernel(); + tty_unlock(); goto retry_open; } - unlock_kernel(); + tty_unlock(); mutex_lock(&tty_mutex); - lock_kernel(); + tty_lock(); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -1890,7 +1896,7 @@ got_driver: tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return 0; } @@ -1926,13 +1932,12 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) return ret; } -static int tty_fasync(int fd, struct file *filp, int on) +static int __tty_fasync(int fd, struct file *filp, int on) { struct tty_struct *tty; unsigned long flags; int retval = 0; - lock_kernel(); tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync")) goto out; @@ -1966,7 +1971,15 @@ static int tty_fasync(int fd, struct file *filp, int on) } retval = 0; out: - unlock_kernel(); + return retval; +} + +static int tty_fasync(int fd, struct file *filp, int on) +{ + int retval; + tty_lock(); + retval = __tty_fasync(fd, filp, on); + tty_unlock(); return retval; } |