pty: Fix packet mode setting race
[firefly-linux-kernel-4.4.55.git] / drivers / tty / pty.c
index 7f612c524224740451e4b18cd0618cef663c7692..bcec4c71a408cd60832d1f1bcf4fdc32e174c777 100644 (file)
@@ -178,21 +178,21 @@ static int pty_get_lock(struct tty_struct *tty, int __user *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);
+       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;
-       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+       spin_unlock_irq(&tty->ctrl_lock);
 
        return 0;
 }
@@ -221,16 +221,15 @@ static int pty_signal(struct tty_struct *tty, int sig)
 static void pty_flush_buffer(struct tty_struct *tty)
 {
        struct tty_struct *to = tty->link;
-       unsigned long flags;
 
        if (!to)
                return;
        /* tty_buffer_flush(to); FIXME */
        if (to->packet) {
-               spin_lock_irqsave(&tty->ctrl_lock, flags);
+               spin_lock_irq(&tty->ctrl_lock);
                tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
                wake_up_interruptible(&to->read_wait);
-               spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+               spin_unlock_irq(&tty->ctrl_lock);
        }
 }
 
@@ -259,8 +258,6 @@ out:
 static void pty_set_termios(struct tty_struct *tty,
                                        struct ktermios *old_termios)
 {
-       unsigned long flags;
-
        /* See if packet mode change of state. */
        if (tty->link && tty->link->packet) {
                int extproc = (old_termios->c_lflag & EXTPROC) |
@@ -272,7 +269,7 @@ static void pty_set_termios(struct tty_struct *tty,
                                STOP_CHAR(tty) == '\023' &&
                                START_CHAR(tty) == '\021');
                if ((old_flow != new_flow) || extproc) {
-                       spin_lock_irqsave(&tty->ctrl_lock, flags);
+                       spin_lock_irq(&tty->ctrl_lock);
                        if (old_flow != new_flow) {
                                tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
                                if (new_flow)
@@ -282,7 +279,7 @@ static void pty_set_termios(struct tty_struct *tty,
                        }
                        if (extproc)
                                tty->ctrl_status |= TIOCPKT_IOCTL;
-                       spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+                       spin_unlock_irq(&tty->ctrl_lock);
                        wake_up_interruptible(&tty->link->read_wait);
                }
        }
@@ -343,26 +340,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);
 }
 
 /**