1. 28 6月, 2018 1 次提交
  2. 28 2月, 2018 1 次提交
    • T
      tty: make n_tty_read() always abort if hangup is in progress · 28b0f8a6
      Tejun Heo 提交于
      A tty is hung up by __tty_hangup() setting file->f_op to
      hung_up_tty_fops, which is skipped on ttys whose write operation isn't
      tty_write().  This means that, for example, /dev/console whose write
      op is redirected_tty_write() is never actually marked hung up.
      
      Because n_tty_read() uses the hung up status to decide whether to
      abort the waiting readers, the lack of hung-up marking can lead to the
      following scenario.
      
       1. A session contains two processes.  The leader and its child.  The
          child ignores SIGHUP.
      
       2. The leader exits and starts disassociating from the controlling
          terminal (/dev/console).
      
       3. __tty_hangup() skips setting f_op to hung_up_tty_fops.
      
       4. SIGHUP is delivered and ignored.
      
       5. tty_ldisc_hangup() is invoked.  It wakes up the waits which should
          clear the read lockers of tty->ldisc_sem.
      
       6. The reader wakes up but because tty_hung_up_p() is false, it
          doesn't abort and goes back to sleep while read-holding
          tty->ldisc_sem.
      
       7. The leader progresses to tty_ldisc_lock() in tty_ldisc_hangup()
          and is now stuck in D sleep indefinitely waiting for
          tty->ldisc_sem.
      
      The following is Alan's explanation on why some ttys aren't hung up.
      
       http://lkml.kernel.org/r/20171101170908.6ad08580@alans-desktop
      
       1. It broke the serial consoles because they would hang up and close
          down the hardware. With tty_port that *should* be fixable properly
          for any cases remaining.
      
       2. The console layer was (and still is) completely broken and doens't
          refcount properly. So if you turn on console hangups it breaks (as
          indeed does freeing consoles and half a dozen other things).
      
      As neither can be fixed quickly, this patch works around the problem
      by introducing a new flag, TTY_HUPPING, which is used solely to tell
      n_tty_read() that hang-up is in progress for the console and the
      readers should be aborted regardless of the hung-up status of the
      device.
      
      The following is a sample hung task warning caused by this issue.
      
        INFO: task agetty:2662 blocked for more than 120 seconds.
              Not tainted 4.11.3-dbg-tty-lockup-02478-gfd6c7ee-dirty #28
        "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
            0  2662      1 0x00000086
        Call Trace:
         __schedule+0x267/0x890
         schedule+0x36/0x80
         schedule_timeout+0x23c/0x2e0
         ldsem_down_write+0xce/0x1f6
         tty_ldisc_lock+0x16/0x30
         tty_ldisc_hangup+0xb3/0x1b0
         __tty_hangup+0x300/0x410
         disassociate_ctty+0x6c/0x290
         do_exit+0x7ef/0xb00
         do_group_exit+0x3f/0xa0
         get_signal+0x1b3/0x5d0
         do_signal+0x28/0x660
         exit_to_usermode_loop+0x46/0x86
         do_syscall_64+0x9c/0xb0
         entry_SYSCALL64_slow_path+0x25/0x25
      
      The following is the repro.  Run "$PROG /dev/console".  The parent
      process hangs in D state.
      
        #include <sys/types.h>
        #include <sys/stat.h>
        #include <sys/wait.h>
        #include <sys/ioctl.h>
        #include <fcntl.h>
        #include <unistd.h>
        #include <stdio.h>
        #include <stdlib.h>
        #include <errno.h>
        #include <signal.h>
        #include <time.h>
        #include <termios.h>
      
        int main(int argc, char **argv)
        {
      	  struct sigaction sact = { .sa_handler = SIG_IGN };
      	  struct timespec ts1s = { .tv_sec = 1 };
      	  pid_t pid;
      	  int fd;
      
      	  if (argc < 2) {
      		  fprintf(stderr, "test-hung-tty /dev/$TTY\n");
      		  return 1;
      	  }
      
      	  /* fork a child to ensure that it isn't already the session leader */
      	  pid = fork();
      	  if (pid < 0) {
      		  perror("fork");
      		  return 1;
      	  }
      
      	  if (pid > 0) {
      		  /* top parent, wait for everyone */
      		  while (waitpid(-1, NULL, 0) >= 0)
      			  ;
      		  if (errno != ECHILD)
      			  perror("waitpid");
      		  return 0;
      	  }
      
      	  /* new session, start a new session and set the controlling tty */
      	  if (setsid() < 0) {
      		  perror("setsid");
      		  return 1;
      	  }
      
      	  fd = open(argv[1], O_RDWR);
      	  if (fd < 0) {
      		  perror("open");
      		  return 1;
      	  }
      
      	  if (ioctl(fd, TIOCSCTTY, 1) < 0) {
      		  perror("ioctl");
      		  return 1;
      	  }
      
      	  /* fork a child, sleep a bit and exit */
      	  pid = fork();
      	  if (pid < 0) {
      		  perror("fork");
      		  return 1;
      	  }
      
      	  if (pid > 0) {
      		  nanosleep(&ts1s, NULL);
      		  printf("Session leader exiting\n");
      		  exit(0);
      	  }
      
      	  /*
      	   * The child ignores SIGHUP and keeps reading from the controlling
      	   * tty.  Because SIGHUP is ignored, the child doesn't get killed on
      	   * parent exit and the bug in n_tty makes the read(2) block the
      	   * parent's control terminal hangup attempt.  The parent ends up in
      	   * D sleep until the child is explicitly killed.
      	   */
      	  sigaction(SIGHUP, &sact, NULL);
      	  printf("Child reading tty\n");
      	  while (1) {
      		  char buf[1024];
      
      		  if (read(fd, buf, sizeof(buf)) < 0) {
      			  perror("read");
      			  return 1;
      		  }
      	  }
      
      	  return 0;
        }
      Signed-off-by: NTejun Heo <tj@kernel.org>
      Cc: Alan Cox <alan@llwyncelyn.cymru>
      Cc: stable@vger.kernel.org
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      28b0f8a6
  3. 12 2月, 2018 1 次提交
    • L
      vfs: do bulk POLL* -> EPOLL* replacement · a9a08845
      Linus Torvalds 提交于
      This is the mindless scripted replacement of kernel use of POLL*
      variables as described by Al, done by this script:
      
          for V in IN OUT PRI ERR RDNORM RDBAND WRNORM WRBAND HUP RDHUP NVAL MSG; do
              L=`git grep -l -w POLL$V | grep -v '^t' | grep -v /um/ | grep -v '^sa' | grep -v '/poll.h$'|grep -v '^D'`
              for f in $L; do sed -i "-es/^\([^\"]*\)\(\<POLL$V\>\)/\\1E\\2/" $f; done
          done
      
      with de-mangling cleanups yet to come.
      
      NOTE! On almost all architectures, the EPOLL* constants have the same
      values as the POLL* constants do.  But they keyword here is "almost".
      For various bad reasons they aren't the same, and epoll() doesn't
      actually work quite correctly in some cases due to this on Sparc et al.
      
      The next patch from Al will sort out the final differences, and we
      should be all done.
      Scripted-by: NAl Viro <viro@zeniv.linux.org.uk>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      a9a08845
  4. 21 12月, 2017 1 次提交
    • L
      n_tty: fix EXTPROC vs ICANON interaction with TIOCINQ (aka FIONREAD) · 966031f3
      Linus Torvalds 提交于
      We added support for EXTPROC back in 2010 in commit 26df6d13 ("tty:
      Add EXTPROC support for LINEMODE") and the intent was to allow it to
      override some (all?) ICANON behavior.  Quoting from that original commit
      message:
      
               There is a new bit in the termios local flag word, EXTPROC.
               When this bit is set, several aspects of the terminal driver
               are disabled.  Input line editing, character echo, and mapping
               of signals are all disabled.  This allows the telnetd to turn
               off these functions when in linemode, but still keep track of
               what state the user wants the terminal to be in.
      
      but the problem turns out that "several aspects of the terminal driver
      are disabled" is a bit ambiguous, and you can really confuse the n_tty
      layer by setting EXTPROC and then causing some of the ICANON invariants
      to no longer be maintained.
      
      This fixes at least one such case (TIOCINQ) becoming unhappy because of
      the confusion over whether ICANON really means ICANON when EXTPROC is set.
      
      This basically makes TIOCINQ match the case of read: if EXTPROC is set,
      we ignore ICANON.  Also, make sure to reset the ICANON state ie EXTPROC
      changes, not just if ICANON changes.
      
      Fixes: 26df6d13 ("tty: Add EXTPROC support for LINEMODE")
      Reported-by: NTetsuo Handa <penguin-kernel@i-love.sakura.ne.jp>
      Reported-by: Nsyzkaller <syzkaller@googlegroups.com>
      Cc: Jiri Slaby <jslaby@suse.com>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      966031f3
  5. 29 11月, 2017 1 次提交
  6. 08 11月, 2017 2 次提交
    • G
      tty: Remove redundant license text · e5656d43
      Greg Kroah-Hartman 提交于
      Now that the SPDX tag is in all tty files, that identifies the license
      in a specific and legally-defined manner.  So the extra GPL text wording
      can be removed as it is no longer needed at all.
      
      This is done on a quest to remove the 700+ different ways that files in
      the kernel describe the GPL license text.  And there's unneeded stuff
      like the address (sometimes incorrect) for the FSF which is never
      needed.
      
      No copyright headers or other non-license-description text was removed.
      
      Cc: Jiri Slaby <jslaby@suse.com>
      Cc: James Hogan <jhogan@kernel.org>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      e5656d43
    • G
      tty: add SPDX identifiers to all remaining files in drivers/tty/ · e3b3d0f5
      Greg Kroah-Hartman 提交于
      It's good to have SPDX identifiers in all files to make it easier to
      audit the kernel tree for correct licenses.
      
      Update the drivers/tty files files with the correct SPDX license
      identifier based on the license text in the file itself.  The SPDX
      identifier is a legally binding shorthand, which can be used instead of
      the full boiler plate text.
      
      This work is based on a script and data from Thomas Gleixner, Philippe
      Ombredanne, and Kate Stewart.
      
      Cc: Jiri Slaby <jslaby@suse.com>
      Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
      Cc: Paul Mackerras <paulus@samba.org>
      Cc: Michael Ellerman <mpe@ellerman.id.au>
      Cc: Chris Metcalf <cmetcalf@mellanox.com>
      Cc: Jiri Kosina <jikos@kernel.org>
      Cc: David Sterba <dsterba@suse.com>
      Cc: James Hogan <jhogan@kernel.org>
      Cc: Rob Herring <robh@kernel.org>
      Cc: Eric Anholt <eric@anholt.net>
      Cc: Stefan Wahren <stefan.wahren@i2se.com>
      Cc: Florian Fainelli <f.fainelli@gmail.com>
      Cc: Ray Jui <rjui@broadcom.com>
      Cc: Scott Branden <sbranden@broadcom.com>
      Cc: bcm-kernel-feedback-list@broadcom.com
      Cc: "James E.J. Bottomley" <jejb@parisc-linux.org>
      Cc: Helge Deller <deller@gmx.de>
      Cc: Joachim Eastwood <manabian@gmail.com>
      Cc: Matthias Brugger <matthias.bgg@gmail.com>
      Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
      Cc: Tobias Klauser <tklauser@distanz.ch>
      Cc: Russell King <linux@armlinux.org.uk>
      Cc: Vineet Gupta <vgupta@synopsys.com>
      Cc: Richard Genoud <richard.genoud@gmail.com>
      Cc: Alexander Shiyan <shc_work@mail.ru>
      Cc: Baruch Siach <baruch@tkos.co.il>
      Cc: "Maciej W. Rozycki" <macro@linux-mips.org>
      Cc: "Uwe Kleine-König" <kernel@pengutronix.de>
      Cc: Pat Gefre <pfg@sgi.com>
      Cc: "Guilherme G. Piccoli" <gpiccoli@linux.vnet.ibm.com>
      Cc: Jason Wessel <jason.wessel@windriver.com>
      Cc: Vladimir Zapolskiy <vz@mleia.com>
      Cc: Sylvain Lemieux <slemieux.tyco@gmail.com>
      Cc: Carlo Caione <carlo@caione.org>
      Cc: Kevin Hilman <khilman@baylibre.com>
      Cc: Liviu Dudau <liviu.dudau@arm.com>
      Cc: Sudeep Holla <sudeep.holla@arm.com>
      Cc: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
      Cc: Andy Gross <andy.gross@linaro.org>
      Cc: David Brown <david.brown@linaro.org>
      Cc: "Andreas Färber" <afaerber@suse.de>
      Cc: Kevin Cernekee <cernekee@gmail.com>
      Cc: Laxman Dewangan <ldewangan@nvidia.com>
      Cc: Thierry Reding <thierry.reding@gmail.com>
      Cc: Jonathan Hunter <jonathanh@nvidia.com>
      Cc: Barry Song <baohua@kernel.org>
      Cc: Patrice Chotard <patrice.chotard@st.com>
      Cc: Maxime Coquelin <mcoquelin.stm32@gmail.com>
      Cc: Alexandre Torgue <alexandre.torgue@st.com>
      Cc: "David S. Miller" <davem@davemloft.net>
      Cc: Peter Korsgaard <jacmet@sunsite.dk>
      Cc: Timur Tabi <timur@tabi.org>
      Cc: Tony Prisk <linux@prisktech.co.nz>
      Cc: Michal Simek <michal.simek@xilinx.com>
      Cc: "Sören Brinkmann" <soren.brinkmann@xilinx.com>
      Cc: Thomas Gleixner <tglx@linutronix.de>
      Cc: Kate Stewart <kstewart@linuxfoundation.org>
      Cc: Philippe Ombredanne <pombredanne@nexb.com>
      Cc: Jiri Slaby <jslaby@suse.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      e3b3d0f5
  7. 02 5月, 2016 1 次提交
  8. 29 1月, 2016 6 次提交
    • P
      n_tty: Ignore all read data when closing · 7f71b2c1
      Peter Hurley 提交于
      On final port close (and thus final tty close), only output flow
      control requests in the input data should be processed. Ignore all
      other input data, including parity errors, overruns and breaks.
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      7f71b2c1
    • P
      tty: n_tty: fix SIGIO for output · 87108bc9
      Peter Hurley 提交于
      According to fcntl(2), "a SIGIO signal is sent whenever input
      or output becomes possible on that file descriptor", i.e.
      after the output buffer was full and now has space for new data.
      But in fact SIGIO is sent after every write.
      
      n_tty_write() should set TTY_DO_WRITE_WAKEUP only when
      not all data could be written to the buffer.
      
      [pjh: Also fixes missed SIGIO if amt written just happens to be
      [     amount still to write
      Signed-off-by: NJohannes Stezenbach <js@sig21.net>
      [pjh: minor patch edits and re-submit]
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      87108bc9
    • P
      n_tty: Remove tty count checks from unthrottle · ffb91a45
      Peter Hurley 提交于
      Since n_tty_check_unthrottle() is only called from n_tty_read()
      which only originates from a userspace read(), the tty count cannot
      be 0; the read() guarantees the file descriptor has not yet been
      released.
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      ffb91a45
    • P
      n_tty: Fix stuck write wakeup · 7bccc365
      Peter Hurley 提交于
      If signal-driven i/o is disabled while write wakeup is pending (ie.,
      n_tty_write() has set TTY_DO_WRITE_WAKEUP but then signal-driven i/o
      is disabled), the TTY_DO_WRITE_WAKEUP bit will never be cleared and
      will cause tty_wakeup() to always call n_tty_write_wakeup.
      
      Unconditionally clear the write wakeup, and since kill_fasync()
      already checks if the fasync ptr is null, call kill_fasync()
      unconditionally as well.
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      7bccc365
    • P
      tty, n_tty: Remove fasync() ldisc notification · bee6741c
      Peter Hurley 提交于
      Only the N_TTY line discipline implements the signal-driven i/o
      notification enabled/disabled by fcntl(F_SETFL, O_ASYNC). The ldisc
      fasync() notification is sent to the ldisc when the enable state has
      changed (the tty core is notified via the fasync() VFS file operation).
      
      The N_TTY line discipline used the enable state to change the wakeup
      condition (minimum_to_wake = 1) for notifying the signal handler i/o is
      available. However, just the presence of data is sufficient and necessary
      to signal i/o is available, so changing minimum_to_wake is unnecessary
      (and creates a race condition with read() and poll() which may be
      concurrently updating minimum_to_wake).
      
      Furthermore, since the kill_fasync() VFS helper performs no action if
      the fasync list is empty, calling unconditionally is preferred; if
      signal driven i/o just has been disabled, no signal will be sent by
      kill_fasync() anyway so notification of the change via the ldisc
      fasync() method is superfluous.
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      bee6741c
    • P
      n_tty: Always wake up read()/poll() if new input · 33d71363
      Peter Hurley 提交于
      A read() in non-canonical mode when VMIN > 0 and VTIME == 0 does not
      complete until at least VMIN chars have been read (or the user buffer is
      full). In this infrequent read mode, n_tty_read() attempts to reduce
      wakeups by computing the amount of data still necessary to complete the
      read (minimum_to_wake) and only waking the read()/poll() when that much
      unread data has been processed. This is the only read mode for which
      new data does not necessarily generate a wakeup.
      
      However, this optimization is broken and commonly leads to hung reads
      even though the necessary amount of data has been received. Since the
      optimization is of marginal value anyway, just remove the whole
      thing. This also remedies a race between a concurrent poll() and
      read() in this mode, where the poll() can reset the minimum_to_wake
      of the read() (and vice versa).
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      33d71363
  9. 28 1月, 2016 6 次提交
  10. 27 1月, 2016 1 次提交
  11. 14 12月, 2015 4 次提交
  12. 13 12月, 2015 1 次提交
    • P
      n_tty: Fix poll() after buffer-limited eof push read · ac8f3bf8
      Peter Hurley 提交于
      commit 40d5e090 ("n_tty: Fix EOF push handling") fixed EOF push
      for reads. However, that approach still allows a condition mismatch
      between poll() and read(), where poll() returns POLLIN but read()
      blocks. This state can happen when a previous read() returned because
      the user buffer was full and the next character was an EOF not at the
      beginning of the line. While the next read() will properly identify
      the condition and advance the read buffer tail without improperly
      indicating an EOF file condition (ie., read() will not mistakenly
      return 0), poll() will mistakenly indicate POLLIN.
      
      Although a possible solution would be to peek at the input buffer
      in n_tty_poll(), the better solution in this patch is to eat the
      EOF during the previous read() (ie., fix the problem by eliminating
      the condition).
      
      The current canon line buffer copy limits the scan for next end-of-line
      to the smaller of either,
         a. the remaining user buffer size
         b. completed lines in the input buffer
      When the remaining user buffer size is exactly one less than the
      end-of-line marked by EOF push, the EOF is not scanned nor skipped
      but left for subsequent reads. In the example below, the scan
      index 'eol' has stopped at the EOF because it is past the scan
      limit of 5 (not because it has found the next set bit in read_flags)
      
         user buffer [*nr = 5]    _ _ _ _ _
      
         read_flags               0 0 0 0 0   1
         input buffer             h e l l o [EOF]
                                  ^           ^
                                 /           /
                               tail        eol
      
         result: found = 0, tail += 5, *nr += 5
      
      Instead, allow the scan to peek ahead 1 byte (while still limiting the
      scan to completed lines in the input buffer). For the example above,
      
         result: found = 1, tail += 6, *nr += 5
      
      Because the scan limit is now bumped +1 byte, when the scan is
      completed, the tail advance and the user buffer copy limit is
      re-clamped to *nr when EOF is _not_ found.
      
      Fixes: 40d5e090 ("n_tty: Fix EOF push handling")
      Cc: <stable@vger.kernel.org> # 3.12+
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      ac8f3bf8
  13. 21 11月, 2015 1 次提交
  14. 18 10月, 2015 3 次提交
  15. 05 10月, 2015 1 次提交
    • K
      tty: fix stall caused by missing memory barrier in drivers/tty/n_tty.c · e81107d4
      Kosuke Tatsukawa 提交于
      My colleague ran into a program stall on a x86_64 server, where
      n_tty_read() was waiting for data even if there was data in the buffer
      in the pty.  kernel stack for the stuck process looks like below.
       #0 [ffff88303d107b58] __schedule at ffffffff815c4b20
       #1 [ffff88303d107bd0] schedule at ffffffff815c513e
       #2 [ffff88303d107bf0] schedule_timeout at ffffffff815c7818
       #3 [ffff88303d107ca0] wait_woken at ffffffff81096bd2
       #4 [ffff88303d107ce0] n_tty_read at ffffffff8136fa23
       #5 [ffff88303d107dd0] tty_read at ffffffff81368013
       #6 [ffff88303d107e20] __vfs_read at ffffffff811a3704
       #7 [ffff88303d107ec0] vfs_read at ffffffff811a3a57
       #8 [ffff88303d107f00] sys_read at ffffffff811a4306
       #9 [ffff88303d107f50] entry_SYSCALL_64_fastpath at ffffffff815c86d7
      
      There seems to be two problems causing this issue.
      
      First, in drivers/tty/n_tty.c, __receive_buf() stores the data and
      updates ldata->commit_head using smp_store_release() and then checks
      the wait queue using waitqueue_active().  However, since there is no
      memory barrier, __receive_buf() could return without calling
      wake_up_interactive_poll(), and at the same time, n_tty_read() could
      start to wait in wait_woken() as in the following chart.
      
              __receive_buf()                         n_tty_read()
      ------------------------------------------------------------------------
      if (waitqueue_active(&tty->read_wait))
      /* Memory operations issued after the
         RELEASE may be completed before the
         RELEASE operation has completed */
                                              add_wait_queue(&tty->read_wait, &wait);
                                              ...
                                              if (!input_available_p(tty, 0)) {
      smp_store_release(&ldata->commit_head,
                        ldata->read_head);
                                              ...
                                              timeout = wait_woken(&wait,
                                                TASK_INTERRUPTIBLE, timeout);
      ------------------------------------------------------------------------
      
      The second problem is that n_tty_read() also lacks a memory barrier
      call and could also cause __receive_buf() to return without calling
      wake_up_interactive_poll(), and n_tty_read() to wait in wait_woken()
      as in the chart below.
      
              __receive_buf()                         n_tty_read()
      ------------------------------------------------------------------------
                                              spin_lock_irqsave(&q->lock, flags);
                                              /* from add_wait_queue() */
                                              ...
                                              if (!input_available_p(tty, 0)) {
                                              /* Memory operations issued after the
                                                 RELEASE may be completed before the
                                                 RELEASE operation has completed */
      smp_store_release(&ldata->commit_head,
                        ldata->read_head);
      if (waitqueue_active(&tty->read_wait))
                                              __add_wait_queue(q, wait);
                                              spin_unlock_irqrestore(&q->lock,flags);
                                              /* from add_wait_queue() */
                                              ...
                                              timeout = wait_woken(&wait,
                                                TASK_INTERRUPTIBLE, timeout);
      ------------------------------------------------------------------------
      
      There are also other places in drivers/tty/n_tty.c which have similar
      calls to waitqueue_active(), so instead of adding many memory barrier
      calls, this patch simply removes the call to waitqueue_active(),
      leaving just wake_up*() behind.
      
      This fixes both problems because, even though the memory access before
      or after the spinlocks in both wake_up*() and add_wait_queue() can
      sneak into the critical section, it cannot go past it and the critical
      section assures that they will be serialized (please see "INTER-CPU
      ACQUIRING BARRIER EFFECTS" in Documentation/memory-barriers.txt for a
      better explanation).  Moreover, the resulting code is much simpler.
      
      Latency measurement using a ping-pong test over a pty doesn't show any
      visible performance drop.
      Signed-off-by: NKosuke Tatsukawa <tatsu@ab.jp.nec.com>
      Cc: stable@vger.kernel.org
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      e81107d4
  16. 24 7月, 2015 2 次提交
  17. 01 6月, 2015 1 次提交
  18. 25 5月, 2015 1 次提交
  19. 11 5月, 2015 1 次提交
    • P
      pty: Fix input race when closing · 1a48632f
      Peter Hurley 提交于
      A read() from a pty master may mistakenly indicate EOF (errno == -EIO)
      after the pty slave has closed, even though input data remains to be read.
      For example,
      
             pty slave       |        input worker        |    pty master
                             |                            |
                             |                            |   n_tty_read()
      pty_write()            |                            |     input avail? no
        add data             |                            |     sleep
        schedule worker  --->|                            |     .
                             |---> flush_to_ldisc()       |     .
      pty_close()            |       fill read buffer     |     .
        wait for worker      |       wakeup reader    --->|     .
                             |       read buffer full?    |---> input avail ? yes
                             |<---   yes - exit worker    |     copy 4096 bytes to user
        TTY_OTHER_CLOSED <---|                            |<--- kick worker
                             |                            |
      
      		                **** New read() before worker starts ****
      
                             |                            |   n_tty_read()
                             |                            |     input avail? no
                             |                            |     TTY_OTHER_CLOSED? yes
                             |                            |     return -EIO
      
      Several conditions are required to trigger this race:
      1. the ldisc read buffer must become full so the input worker exits
      2. the read() count parameter must be >= 4096 so the ldisc read buffer
         is empty
      3. the subsequent read() occurs before the kicked worker has processed
         more input
      
      However, the underlying cause of the race is that data is pipelined, while
      tty state is not; ie., data already written by the pty slave end is not
      yet visible to the pty master end, but state changes by the pty slave end
      are visible to the pty master end immediately.
      
      Pipeline the TTY_OTHER_CLOSED state through input worker to the reader.
      1. Introduce TTY_OTHER_DONE which is set by the input worker when
         TTY_OTHER_CLOSED is set and either the input buffers are flushed or
         input processing has completed. Readers/polls are woken when
         TTY_OTHER_DONE is set.
      2. Reader/poll checks TTY_OTHER_DONE instead of TTY_OTHER_CLOSED.
      3. A new input worker is started from pty_close() after setting
         TTY_OTHER_CLOSED, which ensures the TTY_OTHER_DONE state will be
         set if the last input worker is already finished (or just about to
         exit).
      
      Remove tty_flush_to_ldisc(); no in-tree callers.
      
      Fixes: 52bce7f8 ("pty, n_tty: Simplify input processing on final close")
      Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=96311
      BugLink: http://bugs.launchpad.net/bugs/1429756
      Cc: <stable@vger.kernel.org> # 3.19+
      Reported-by: NAndy Whitcroft <apw@canonical.com>
      Reported-by: NH.J. Lu <hjl.tools@gmail.com>
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      1a48632f
  20. 07 5月, 2015 1 次提交
  21. 03 2月, 2015 3 次提交
    • P
      n_tty: Fix signal handling flushes · d2b6f447
      Peter Hurley 提交于
      BRKINT and ISIG requires input and output flush when a signal char
      is received. However, the order of operations is significant since
      parallel i/o may be ongoing.
      
      Merge the signal handling for BRKINT with ISIG handling.
      
      Process the signal first. This ensures any ongoing i/o is aborted;
      without this, a waiting writer may continue writing after the flush
      occurs and after the signal char has been echoed.
      
      Write lock the termios_rwsem, which excludes parallel writers from
      pushing new i/o until after the output buffers are flushed; claiming
      the write lock is necessary anyway to exclude parallel readers while
      the read buffer is flushed.
      
      Subclass the termios_rwsem for ptys since the slave pty performing
      the flush may appear to reorder the termios_rwsem->tty buffer lock
      lock order; adding annotation clarifies that
        slave tty_buffer lock-> slave termios_rwsem -> master tty_buffer lock
      is a valid lock order.
      
      Flush the echo buffer. In this context, the echo buffer is 'output'.
      Otherwise, the output will appear discontinuous because the output buffer
      was cleared which contains older output than the echo buffer.
      
      Open-code the read buffer flush since the input worker does not need
      kicking (this is the input worker).
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      d2b6f447
    • P
      n_tty: Fix read buffer overwrite when no newline · fb5ef9e7
      Peter Hurley 提交于
      In canon mode, the read buffer head will advance over the buffer tail
      if the input > 4095 bytes without receiving a line termination char.
      
      Discard additional input until a line termination is received.
      Before evaluating for overflow, the 'room' value is normalized for
      I_PARMRK and 1 byte is reserved for line termination (even in !icanon
      mode, in case the mode is switched). The following table shows the
      transform:
      
       actual buffer |  'room' value before overflow calc
        space avail  |    !I_PARMRK    |    I_PARMRK
       --------------------------------------------------
            0        |       -1        |       -1
            1        |        0        |        0
            2        |        1        |        0
            3        |        2        |        0
            4+       |        3        |        1
      
      When !icanon or when icanon and the read buffer contains newlines,
      normalized 'room' values of -1 and 0 are clamped to 0, and
      'overflow' is 0, so read_head is not adjusted and the input i/o loop
      exits (setting no_room if called from flush_to_ldisc()). No input
      is discarded since the reader does have input available to read
      which ensures forward progress.
      
      When icanon and the read buffer does not contain newlines and the
      normalized 'room' value is 0, then overflow and room are reset to 1,
      so that the i/o loop will process the next input char normally
      (except for parity errors which are ignored). Thus, erasures, signalling
      chars, 7-bit mode, etc. will continue to be handled properly.
      
      If the input char processed was not a line termination char, then
      the canon_head index will not have advanced, so the normalized 'room'
      value will now be -1 and 'overflow' will be set, which indicates the
      read_head can safely be reset, effectively erasing the last char
      processed.
      
      If the input char processed was a line termination, then the
      canon_head index will have advanced, so 'overflow' is cleared to 0,
      the read_head is not reset, and 'room' is cleared to 0, which exits
      the i/o loop (because the reader now have input available to read
      which ensures forward progress).
      
      Note that it is possible for a line termination to be received, and
      for the reader to copy the line to the user buffer before the
      input i/o loop is ready to process the next input char. This is
      why the i/o loop recomputes the room/overflow state with every
      input char while handling overflow.
      
      Finally, if the input data was processed without receiving
      a line termination (so that overflow is still set), the pty
      driver must receive a write wakeup. A pty writer may be waiting
      to write more data in n_tty_write() but without unthrottling
      here that wakeup will not arrive, and forward progress will halt.
      (Normally, the pty writer is woken when the reader reads data out
      of the buffer and more space become available).
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      fb5ef9e7
    • P
      n_tty: Fix PARMRK over-throttling · 06c49f9f
      Peter Hurley 提交于
      If PARMRK is enabled, the available read buffer space computation is
      overly-pessimistic, which results in severely throttled i/o, even
      in the absence of parity errors. For example, if the 4k read buffer
      contains 1k processed data, the input worker will compute available
      space of 333 bytes, despite 3k being available. At 1365 chars of
      processed data, 0 space available is computed.
      
      *Divide remaining space* by 3, truncating down (if left == 2, left = 0).
      Reported-by: NChristian Riesch <christian.riesch@omicron.at>
      
      Conflicts:
      	drivers/tty/n_tty.c
      Signed-off-by: NPeter Hurley <peter@hurleysoftware.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      06c49f9f