Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm...
[firefly-linux-kernel-4.4.55.git] / drivers / tty / pty.c
index 29b5eeb018560e6f763cd68a6d28e987d5bcebcd..a9d256d6e909c1aecfc854732694d608256aeb15 100644 (file)
@@ -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);
        }
 }
 
@@ -186,8 +187,9 @@ static int pty_set_pktmode(struct tty_struct *tty, int __user *arg)
        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;
@@ -339,26 +341,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);
 }
 
 /**
@@ -380,6 +382,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])
@@ -392,6 +398,8 @@ 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);
+
        if (legacy) {
                /* We always use new tty termios data so we can do this
                   the easy way .. */
@@ -416,8 +424,6 @@ 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;
@@ -429,6 +435,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
 
        tty_driver_kref_get(driver);
        tty->count++;
+       o_tty->count++;
        return 0;
 err_free_termios:
        if (legacy)