drm/rockchip: vop: make windows disable take effect
[firefly-linux-kernel-4.4.55.git] / drivers / tty / tty_io.c
index 2eefaa6e3e3a4af9a5ab2b03cf03f9e75a04ca1d..7cef54334b122d22d9f610cacf0a126b615872a8 100644 (file)
@@ -390,10 +390,10 @@ EXPORT_SYMBOL_GPL(tty_find_polling_driver);
  *     Locking: ctrl_lock
  */
 
-int tty_check_change(struct tty_struct *tty)
+int __tty_check_change(struct tty_struct *tty, int sig)
 {
        unsigned long flags;
-       struct pid *pgrp;
+       struct pid *pgrp, *tty_pgrp;
        int ret = 0;
 
        if (current->signal->tty != tty)
@@ -403,33 +403,35 @@ int tty_check_change(struct tty_struct *tty)
        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 (pgrp == tty->pgrp)
-               goto out_unlock;
+       tty_pgrp = tty->pgrp;
        spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 
-       if (is_ignored(SIGTTOU))
-               goto out_rcuunlock;
-       if (is_current_pgrp_orphaned()) {
-               ret = -EIO;
-               goto out_rcuunlock;
+       if (tty_pgrp && pgrp != tty->pgrp) {
+               if (is_ignored(sig)) {
+                       if (sig == SIGTTIN)
+                               ret = -EIO;
+               } else if (is_current_pgrp_orphaned())
+                       ret = -EIO;
+               else {
+                       kill_pgrp(pgrp, sig, 1);
+                       set_thread_flag(TIF_SIGPENDING);
+                       ret = -ERESTARTSYS;
+               }
        }
-       kill_pgrp(pgrp, SIGTTOU, 1);
-       rcu_read_unlock();
-       set_thread_flag(TIF_SIGPENDING);
-       ret = -ERESTARTSYS;
-       return ret;
-out_unlock:
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-out_rcuunlock:
        rcu_read_unlock();
+
+       if (!tty_pgrp) {
+               pr_warn("%s: tty_check_change: sig=%d, tty->pgrp == NULL!\n",
+                       tty_name(tty), sig);
+       }
+
        return ret;
 }
 
+int tty_check_change(struct tty_struct *tty)
+{
+       return __tty_check_change(tty, SIGTTOU);
+}
 EXPORT_SYMBOL(tty_check_change);
 
 static ssize_t hung_up_tty_read(struct file *file, char __user *buf,
@@ -1198,11 +1200,9 @@ void tty_write_message(struct tty_struct *tty, char *msg)
        if (tty) {
                mutex_lock(&tty->atomic_write_lock);
                tty_lock(tty);
-               if (tty->ops->write && tty->count > 0) {
-                       tty_unlock(tty);
+               if (tty->ops->write && tty->count > 0)
                        tty->ops->write(tty, msg, strlen(msg));
-               } else
-                       tty_unlock(tty);
+               tty_unlock(tty);
                tty_write_unlock(tty);
        }
        return;
@@ -1282,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;
 }
@@ -1458,13 +1462,13 @@ static int tty_reopen(struct tty_struct *tty)
 {
        struct tty_driver *driver = tty->driver;
 
-       if (!tty->count)
-               return -EIO;
-
        if (driver->type == TTY_DRIVER_TYPE_PTY &&
            driver->subtype == PTY_TYPE_MASTER)
                return -EIO;
 
+       if (!tty->count)
+               return -EAGAIN;
+
        if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
                return -EBUSY;
 
@@ -1689,7 +1693,7 @@ static void release_tty(struct tty_struct *tty, int idx)
        tty->port->itty = NULL;
        if (tty->link)
                tty->link->port->itty = NULL;
-       cancel_work_sync(&tty->port->buf.work);
+       tty_buffer_cancel_work(tty->port);
 
        tty_kref_put(tty->link);
        tty_kref_put(tty);
@@ -2065,7 +2069,12 @@ retry_open:
 
                if (tty) {
                        mutex_unlock(&tty_mutex);
-                       tty_lock(tty);
+                       retval = tty_lock_interruptible(tty);
+                       if (retval) {
+                               if (retval == -EINTR)
+                                       retval = -ERESTARTSYS;
+                               goto err_unref;
+                       }
                        /* safe to drop the kref from tty_driver_lookup_tty() */
                        tty_kref_put(tty);
                        retval = tty_reopen(tty);
@@ -2083,7 +2092,11 @@ retry_open:
 
        if (IS_ERR(tty)) {
                retval = PTR_ERR(tty);
-               goto err_file;
+               if (retval != -EAGAIN || signal_pending(current))
+                       goto err_file;
+               tty_free_file(filp);
+               schedule();
+               goto retry_open;
        }
 
        tty_add_file(tty, filp);
@@ -2152,6 +2165,7 @@ retry_open:
        return 0;
 err_unlock:
        mutex_unlock(&tty_mutex);
+err_unref:
        /* after locks to avoid deadlock */
        if (!IS_ERR_OR_NULL(driver))
                tty_driver_kref_put(driver);
@@ -2569,7 +2583,6 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
        struct pid *pgrp;
        pid_t pgrp_nr;
        int retval = tty_check_change(real_tty);
-       unsigned long flags;
 
        if (retval == -EIO)
                return -ENOTTY;
@@ -2592,10 +2605,10 @@ static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
        if (session_of_pgrp(pgrp) != task_session(current))
                goto out_unlock;
        retval = 0;
-       spin_lock_irqsave(&tty->ctrl_lock, flags);
+       spin_lock_irq(&tty->ctrl_lock);
        put_pid(real_tty->pgrp);
        real_tty->pgrp = get_pid(pgrp);
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       spin_unlock_irq(&tty->ctrl_lock);
 out_unlock:
        rcu_read_unlock();
        return retval;
@@ -2649,6 +2662,28 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
        return ret;
 }
 
+/**
+ *     tiocgetd        -       get line discipline
+ *     @tty: tty device
+ *     @p: pointer to user data
+ *
+ *     Retrieves the line discipline id directly from the ldisc.
+ *
+ *     Locking: waits for ldisc reference (in case the line discipline
+ *             is changing or the tty is being hungup)
+ */
+
+static int tiocgetd(struct tty_struct *tty, int __user *p)
+{
+       struct tty_ldisc *ld;
+       int ret;
+
+       ld = tty_ldisc_ref_wait(tty);
+       ret = put_user(ld->ops->num, p);
+       tty_ldisc_deref(ld);
+       return ret;
+}
+
 /**
  *     send_break      -       performed time break
  *     @tty: device to break on
@@ -2875,7 +2910,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
        case TIOCGSID:
                return tiocgsid(tty, real_tty, p);
        case TIOCGETD:
-               return put_user(tty->ldisc->ops->num, (int __user *)p);
+               return tiocgetd(tty, p);
        case TIOCSETD:
                return tiocsetd(tty, p);
        case TIOCVHANGUP: