diff options
author | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-12-15 14:52:16 -0300 |
---|---|---|
committer | André Fabian Silva Delgado <emulatorman@parabola.nu> | 2015-12-15 14:52:16 -0300 |
commit | 8d91c1e411f55d7ea91b1183a2e9f8088fb4d5be (patch) | |
tree | e9891aa6c295060d065adffd610c4f49ecf884f3 /drivers/tty/tty_io.c | |
parent | a71852147516bc1cb5b0b3cbd13639bfd4022dc8 (diff) |
Linux-libre 4.3.2-gnu
Diffstat (limited to 'drivers/tty/tty_io.c')
-rw-r--r-- | drivers/tty/tty_io.c | 117 |
1 files changed, 63 insertions, 54 deletions
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 774df354a..f435977de 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -106,6 +106,11 @@ #include <linux/nsproxy.h> #undef TTY_DEBUG_HANGUP +#ifdef TTY_DEBUG_HANGUP +# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) +#else +# define tty_debug_hangup(tty, f, args...) do { } while (0) +#endif #define TTY_PARANOIA_CHECK 1 #define CHECK_TTY_COUNT 1 @@ -388,33 +393,40 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver); int tty_check_change(struct tty_struct *tty) { unsigned long flags; + struct pid *pgrp; int ret = 0; if (current->signal->tty != tty) return 0; + rcu_read_lock(); + pgrp = task_pgrp(current); + spin_lock_irqsave(&tty->ctrl_lock, flags); if (!tty->pgrp) { printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n"); goto out_unlock; } - if (task_pgrp(current) == tty->pgrp) + if (pgrp == tty->pgrp) goto out_unlock; spin_unlock_irqrestore(&tty->ctrl_lock, flags); + if (is_ignored(SIGTTOU)) - goto out; + goto out_rcuunlock; if (is_current_pgrp_orphaned()) { ret = -EIO; - goto out; + goto out_rcuunlock; } - kill_pgrp(task_pgrp(current), SIGTTOU, 1); + kill_pgrp(pgrp, SIGTTOU, 1); + rcu_read_unlock(); set_thread_flag(TIF_SIGPENDING); ret = -ERESTARTSYS; -out: return ret; out_unlock: spin_unlock_irqrestore(&tty->ctrl_lock, flags); +out_rcuunlock: + rcu_read_unlock(); return ret; } @@ -524,7 +536,8 @@ static void __proc_set_tty(struct tty_struct *tty) spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty->session = get_pid(task_session(current)); if (current->signal->tty) { - printk(KERN_DEBUG "tty not NULL!!\n"); + tty_debug(tty, "current tty %s not NULL!!\n", + current->signal->tty->name); tty_kref_put(current->signal->tty); } put_pid(current->signal->tty_old_pgrp); @@ -766,9 +779,7 @@ static void do_tty_hangup(struct work_struct *work) void tty_hangup(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s hangup...\n", tty_name(tty)); -#endif + tty_debug_hangup(tty, "\n"); schedule_work(&tty->hangup_work); } @@ -785,9 +796,7 @@ EXPORT_SYMBOL(tty_hangup); void tty_vhangup(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty)); -#endif + tty_debug_hangup(tty, "\n"); __tty_hangup(tty, 0); } @@ -824,9 +833,7 @@ void tty_vhangup_self(void) static void tty_vhangup_session(struct tty_struct *tty) { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s vhangup session...\n", tty_name(tty)); -#endif + tty_debug_hangup(tty, "\n"); __tty_hangup(tty, 1); } @@ -920,12 +927,8 @@ void disassociate_ctty(int on_exit) tty->pgrp = NULL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty_kref_put(tty); - } else { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "error attempted to write to tty [0x%p]" - " = NULL", tty); -#endif - } + } else + tty_debug_hangup(tty, "no current tty\n"); spin_unlock_irq(¤t->sighand->siglock); /* Now clear signal->tty under the lock */ @@ -1279,18 +1282,22 @@ int tty_send_xchar(struct tty_struct *tty, char ch) int was_stopped = tty->stopped; if (tty->ops->send_xchar) { + down_read(&tty->termios_rwsem); tty->ops->send_xchar(tty, ch); + up_read(&tty->termios_rwsem); return 0; } if (tty_write_lock(tty, 0) < 0) return -ERESTARTSYS; + down_read(&tty->termios_rwsem); if (was_stopped) start_tty(tty); tty->ops->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); + up_read(&tty->termios_rwsem); tty_write_unlock(tty); return 0; } @@ -1705,8 +1712,7 @@ static int tty_release_checks(struct tty_struct *tty, int idx) { #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "%s: bad idx when trying to free (%s)\n", - __func__, tty->name); + tty_debug(tty, "bad idx %d\n", idx); return -1; } @@ -1715,20 +1721,20 @@ static int tty_release_checks(struct tty_struct *tty, int idx) return 0; if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "%s: driver.table[%d] not tty for (%s)\n", - __func__, idx, tty->name); + tty_debug(tty, "bad driver table[%d] = %p\n", + idx, tty->driver->ttys[idx]); return -1; } if (tty->driver->other) { struct tty_struct *o_tty = tty->link; if (o_tty != tty->driver->other->ttys[idx]) { - printk(KERN_DEBUG "%s: other->table[%d] not o_tty for (%s)\n", - __func__, idx, tty->name); + tty_debug(tty, "bad other table[%d] = %p\n", + idx, tty->driver->other->ttys[idx]); return -1; } if (o_tty->link != tty) { - printk(KERN_DEBUG "%s: bad pty pointers\n", __func__); + tty_debug(tty, "bad link = %p\n", o_tty->link); return -1; } } @@ -1782,10 +1788,7 @@ int tty_release(struct inode *inode, struct file *filp) return 0; } -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s (tty count=%d)...\n", __func__, - tty_name(tty), tty->count); -#endif + tty_debug_hangup(tty, "(tty count=%d)...\n", tty->count); if (tty->ops->close) tty->ops->close(tty, filp); @@ -1895,9 +1898,7 @@ int tty_release(struct inode *inode, struct file *filp) if (!final) return 0; -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: final close\n", __func__, tty_name(tty)); -#endif + tty_debug_hangup(tty, "final close\n"); /* * Ask the line discipline code to release its structures */ @@ -1906,10 +1907,7 @@ int tty_release(struct inode *inode, struct file *filp) /* Wait for pending work before tty destruction commmences */ tty_flush_works(tty); -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: %s: freeing structure...\n", __func__, - tty_name(tty)); -#endif + tty_debug_hangup(tty, "freeing structure...\n"); /* * The release_tty function takes care of the details of clearing * the slots and preserving the termios structure. The tty_unlock_pair @@ -2098,9 +2096,9 @@ retry_open: if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) noctty = 1; -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: opening %s...\n", __func__, tty->name); -#endif + + tty_debug_hangup(tty, "(tty count=%d)\n", tty->count); + if (tty->ops->open) retval = tty->ops->open(tty, filp); else @@ -2108,10 +2106,8 @@ retry_open: filp->f_flags = saved_flags; if (retval) { -#ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "%s: error %d in opening %s...\n", __func__, - retval, tty->name); -#endif + tty_debug_hangup(tty, "error %d, releasing...\n", retval); + tty_unlock(tty); /* need to call tty_release without BTM */ tty_release(inode, filp); if (retval != -ERESTARTSYS) @@ -3182,10 +3178,18 @@ struct class *tty_class; static int tty_cdev_add(struct tty_driver *driver, dev_t dev, unsigned int index, unsigned int count) { + int err; + /* init here, since reused cdevs cause crashes */ - cdev_init(&driver->cdevs[index], &tty_fops); - driver->cdevs[index].owner = driver->owner; - return cdev_add(&driver->cdevs[index], dev, count); + driver->cdevs[index] = cdev_alloc(); + if (!driver->cdevs[index]) + return -ENOMEM; + driver->cdevs[index]->ops = &tty_fops; + driver->cdevs[index]->owner = driver->owner; + err = cdev_add(driver->cdevs[index], dev, count); + if (err) + kobject_put(&driver->cdevs[index]->kobj); + return err; } /** @@ -3291,8 +3295,10 @@ struct device *tty_register_device_attr(struct tty_driver *driver, error: put_device(dev); - if (cdev) - cdev_del(&driver->cdevs[index]); + if (cdev) { + cdev_del(driver->cdevs[index]); + driver->cdevs[index] = NULL; + } return ERR_PTR(retval); } EXPORT_SYMBOL_GPL(tty_register_device_attr); @@ -3312,8 +3318,10 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) { device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); - if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) - cdev_del(&driver->cdevs[index]); + if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { + cdev_del(driver->cdevs[index]); + driver->cdevs[index] = NULL; + } } EXPORT_SYMBOL(tty_unregister_device); @@ -3378,6 +3386,7 @@ err_free_all: kfree(driver->ports); kfree(driver->ttys); kfree(driver->termios); + kfree(driver->cdevs); kfree(driver); return ERR_PTR(err); } @@ -3406,7 +3415,7 @@ static void destruct_tty_driver(struct kref *kref) } proc_tty_unregister_driver(driver); if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) - cdev_del(&driver->cdevs[0]); + cdev_del(driver->cdevs[0]); } kfree(driver->cdevs); kfree(driver->ports); |