Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / drivers / tty / n_tty.c
index 396344c..84e71bd 100644 (file)
@@ -169,7 +169,7 @@ static inline int tty_copy_to_user(struct tty_struct *tty,
 {
        struct n_tty_data *ldata = tty->disc_data;
 
-       tty_audit_add_data(tty, to, n, ldata->icanon);
+       tty_audit_add_data(tty, from, n, ldata->icanon);
        return copy_to_user(to, from, n);
 }
 
@@ -201,7 +201,7 @@ static void n_tty_kick_worker(struct tty_struct *tty)
                 */
                WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
                               "scheduling buffer work for halted ldisc\n");
-               queue_work(system_unbound_wq, &tty->port->buf.work);
+               tty_buffer_restart_work(tty->port);
        }
 }
 
@@ -258,16 +258,13 @@ static void n_tty_check_throttle(struct tty_struct *tty)
 
 static void n_tty_check_unthrottle(struct tty_struct *tty)
 {
-       if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
-           tty->link->ldisc->ops->write_wakeup == n_tty_write_wakeup) {
+       if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
                if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
                        return;
                if (!tty->count)
                        return;
                n_tty_kick_worker(tty);
-               n_tty_write_wakeup(tty->link);
-               if (waitqueue_active(&tty->link->write_wait))
-                       wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
+               tty_wakeup(tty->link);
                return;
        }
 
@@ -343,8 +340,7 @@ static void n_tty_packet_mode_flush(struct tty_struct *tty)
                spin_lock_irqsave(&tty->ctrl_lock, flags);
                tty->ctrl_status |= TIOCPKT_FLUSHREAD;
                spin_unlock_irqrestore(&tty->ctrl_lock, flags);
-               if (waitqueue_active(&tty->link->read_wait))
-                       wake_up_interruptible(&tty->link->read_wait);
+               wake_up_interruptible(&tty->link->read_wait);
        }
 }
 
@@ -1108,19 +1104,29 @@ static void eraser(unsigned char c, struct tty_struct *tty)
  *     Locking: ctrl_lock
  */
 
-static void isig(int sig, struct tty_struct *tty)
+static void __isig(int sig, struct tty_struct *tty)
 {
-       struct n_tty_data *ldata = tty->disc_data;
        struct pid *tty_pgrp = tty_get_pgrp(tty);
        if (tty_pgrp) {
                kill_pgrp(tty_pgrp, sig, 1);
                put_pid(tty_pgrp);
        }
+}
 
-       if (!L_NOFLSH(tty)) {
+static void isig(int sig, struct tty_struct *tty)
+{
+       struct n_tty_data *ldata = tty->disc_data;
+
+       if (L_NOFLSH(tty)) {
+               /* signal only */
+               __isig(sig, tty);
+
+       } else { /* signal and flush */
                up_read(&tty->termios_rwsem);
                down_write(&tty->termios_rwsem);
 
+               __isig(sig, tty);
+
                /* clear echo buffer */
                mutex_lock(&ldata->output_lock);
                ldata->echo_head = ldata->echo_tail = 0;
@@ -1170,8 +1176,6 @@ static void n_tty_receive_break(struct tty_struct *tty)
                put_tty_queue('\0', ldata);
        }
        put_tty_queue('\0', ldata);
-       if (waitqueue_active(&tty->read_wait))
-               wake_up_interruptible_poll(&tty->read_wait, POLLIN);
 }
 
 /**
@@ -1190,13 +1194,12 @@ static void n_tty_receive_break(struct tty_struct *tty)
 static void n_tty_receive_overrun(struct tty_struct *tty)
 {
        struct n_tty_data *ldata = tty->disc_data;
-       char buf[64];
 
        ldata->num_overrun++;
        if (time_after(jiffies, ldata->overrun_time + HZ) ||
                        time_after(ldata->overrun_time, jiffies)) {
                printk(KERN_WARNING "%s: %d input overrun(s)\n",
-                       tty_name(tty, buf),
+                       tty_name(tty),
                        ldata->num_overrun);
                ldata->overrun_time = jiffies;
                ldata->num_overrun = 0;
@@ -1229,8 +1232,6 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
                        put_tty_queue('\0', ldata);
        } else
                put_tty_queue(c, ldata);
-       if (waitqueue_active(&tty->read_wait))
-               wake_up_interruptible_poll(&tty->read_wait, POLLIN);
 }
 
 static void
@@ -1373,8 +1374,7 @@ handle_newline:
                        put_tty_queue(c, ldata);
                        smp_store_release(&ldata->canon_head, ldata->read_head);
                        kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-                       if (waitqueue_active(&tty->read_wait))
-                               wake_up_interruptible_poll(&tty->read_wait, POLLIN);
+                       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
                        return 0;
                }
        }
@@ -1471,8 +1471,6 @@ static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c)
 static void
 n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
 {
-       char buf[64];
-
        switch (flag) {
        case TTY_BREAK:
                n_tty_receive_break(tty);
@@ -1486,7 +1484,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag)
                break;
        default:
                printk(KERN_ERR "%s: unknown flag %d\n",
-                      tty_name(tty, buf), flag);
+                      tty_name(tty), flag);
                break;
        }
 }
@@ -1660,8 +1658,7 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
 
        if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
                kill_fasync(&tty->fasync, SIGIO, POLL_IN);
-               if (waitqueue_active(&tty->read_wait))
-                       wake_up_interruptible_poll(&tty->read_wait, POLLIN);
+               wake_up_interruptible_poll(&tty->read_wait, POLLIN);
        }
 }
 
@@ -1880,10 +1877,8 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
        }
 
        /* The termios change make the tty ready for I/O */
-       if (waitqueue_active(&tty->write_wait))
-               wake_up_interruptible(&tty->write_wait);
-       if (waitqueue_active(&tty->read_wait))
-               wake_up_interruptible(&tty->read_wait);
+       wake_up_interruptible(&tty->write_wait);
+       wake_up_interruptible(&tty->read_wait);
 }
 
 /**
@@ -1960,18 +1955,6 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
                return ldata->commit_head - ldata->read_tail >= amt;
 }
 
-static inline int check_other_done(struct tty_struct *tty)
-{
-       int done = test_bit(TTY_OTHER_DONE, &tty->flags);
-       if (done) {
-               /* paired with cmpxchg() in check_other_closed(); ensures
-                * read buffer head index is not stale
-                */
-               smp_mb__after_atomic();
-       }
-       return done;
-}
-
 /**
  *     copy_from_read_buf      -       copy read data directly
  *     @tty: terminal device
@@ -2056,13 +2039,13 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
        size_t eol;
        size_t tail;
        int ret, found = 0;
-       bool eof_push = 0;
 
        /* N.B. avoid overrun if nr == 0 */
-       n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
-       if (!n)
+       if (!*nr)
                return 0;
 
+       n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
+
        tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
        size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
 
@@ -2083,12 +2066,11 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
        n = eol - tail;
        if (n > N_TTY_BUF_SIZE)
                n += N_TTY_BUF_SIZE;
-       n += found;
-       c = n;
+       c = n + found;
 
-       if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) {
-               n--;
-               eof_push = !n && ldata->read_tail != ldata->line_start;
+       if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) {
+               c = min(*nr, c);
+               n = c;
        }
 
        n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
@@ -2118,7 +2100,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
                        ldata->push = 0;
                tty_audit_push(tty);
        }
-       return eof_push ? -EAGAIN : 0;
+       return 0;
 }
 
 extern ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -2145,23 +2127,10 @@ static int job_control(struct tty_struct *tty, struct file *file)
        /* NOTE: not yet done after every sleep pending a thorough
           check of the logic of this change. -- jlc */
        /* don't stop on /dev/console */
-       if (file->f_op->write == redirected_tty_write ||
-           current->signal->tty != tty)
+       if (file->f_op->write == redirected_tty_write)
                return 0;
 
-       spin_lock_irq(&tty->ctrl_lock);
-       if (!tty->pgrp)
-               printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
-       else if (task_pgrp(current) != tty->pgrp) {
-               spin_unlock_irq(&tty->ctrl_lock);
-               if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned())
-                       return -EIO;
-               kill_pgrp(task_pgrp(current), SIGTTIN, 1);
-               set_thread_flag(TIF_SIGPENDING);
-               return -ERESTARTSYS;
-       }
-       spin_unlock_irq(&tty->ctrl_lock);
-       return 0;
+       return __tty_check_change(tty, SIGTTIN);
 }
 
 
@@ -2190,7 +2159,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
        struct n_tty_data *ldata = tty->disc_data;
        unsigned char __user *b = buf;
        DEFINE_WAIT_FUNC(wait, woken_wake_function);
-       int c, done;
+       int c;
        int minimum, time;
        ssize_t retval = 0;
        long timeout;
@@ -2258,40 +2227,40 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
                    ((minimum - (b - buf)) >= 1))
                        ldata->minimum_to_wake = (minimum - (b - buf));
 
-               done = check_other_done(tty);
-
                if (!input_available_p(tty, 0)) {
-                       if (done) {
-                               retval = -EIO;
-                               break;
-                       }
-                       if (tty_hung_up_p(file))
-                               break;
-                       if (!timeout)
-                               break;
-                       if (file->f_flags & O_NONBLOCK) {
-                               retval = -EAGAIN;
-                               break;
-                       }
-                       if (signal_pending(current)) {
-                               retval = -ERESTARTSYS;
-                               break;
-                       }
                        up_read(&tty->termios_rwsem);
+                       tty_buffer_flush_work(tty->port);
+                       down_read(&tty->termios_rwsem);
+                       if (!input_available_p(tty, 0)) {
+                               if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+                                       retval = -EIO;
+                                       break;
+                               }
+                               if (tty_hung_up_p(file))
+                                       break;
+                               if (!timeout)
+                                       break;
+                               if (file->f_flags & O_NONBLOCK) {
+                                       retval = -EAGAIN;
+                                       break;
+                               }
+                               if (signal_pending(current)) {
+                                       retval = -ERESTARTSYS;
+                                       break;
+                               }
+                               up_read(&tty->termios_rwsem);
 
-                       timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
-                                            timeout);
+                               timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
+                                               timeout);
 
-                       down_read(&tty->termios_rwsem);
-                       continue;
+                               down_read(&tty->termios_rwsem);
+                               continue;
+                       }
                }
 
                if (ldata->icanon && !L_EXTPROC(tty)) {
                        retval = canon_copy_from_read_buf(tty, &b, &nr);
-                       if (retval == -EAGAIN) {
-                               retval = 0;
-                               continue;
-                       } else if (retval)
+                       if (retval)
                                break;
                } else {
                        int uncopied;
@@ -2468,12 +2437,17 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 
        poll_wait(file, &tty->read_wait, wait);
        poll_wait(file, &tty->write_wait, wait);
-       if (check_other_done(tty))
-               mask |= POLLHUP;
        if (input_available_p(tty, 1))
                mask |= POLLIN | POLLRDNORM;
+       else {
+               tty_buffer_flush_work(tty->port);
+               if (input_available_p(tty, 1))
+                       mask |= POLLIN | POLLRDNORM;
+       }
        if (tty->packet && tty->link->ctrl_status)
                mask |= POLLPRI | POLLIN | POLLRDNORM;
+       if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+               mask |= POLLHUP;
        if (tty_hung_up_p(file))
                mask |= POLLHUP;
        if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {