1. 04 Apr, 2011 1 commit
    • Linus Torvalds's avatar
      tty: fix endless work loop when the buffer fills up · a5660b41
      Linus Torvalds authored
      Commit f23eb2b2 ('tty: stop using "delayed_work" in the tty layer')
      ended up causing hung machines on UP with no preemption, because the
      work routine to flip the buffer data to the ldisc would endlessly re-arm
      itself if the destination buffer had filled up.
      
      With the delayed work, that only caused a timer-driving polling of the
      tty state every timer tick, but without the delay we just ended up with
      basically a busy loop instead.
      
      Stop the insane polling, and instead make the code that opens up the
      receive room re-schedule the buffer flip work.  That's what we should
      have been doing anyway.
      
      This same "poll for tty room" issue is almost certainly also the cause
      of excessive kworker activity when idle reported by Dave Jones, who also
      reported "flush_to_ldisc executing 2500 times a second" back in Nov 2010:
      
        http://lkml.org/lkml/2010/11/30/592
      
      which is that silly flushing done every timer tick.  Wasting both power
      and CPU for no good reason.
      Reported-and-tested-by: default avatarAlexander Beregalov <a.beregalov@gmail.com>
      Reported-and-tested-by: default avatarSitsofe Wheeler <sitsofe@yahoo.com>
      Cc: Greg KH <gregkh@suse.de>
      Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
      Cc: Dave Jones <davej@redhat.com>
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      a5660b41
  2. 22 Mar, 2011 1 commit
    • Linus Torvalds's avatar
      tty: stop using "delayed_work" in the tty layer · f23eb2b2
      Linus Torvalds authored
      Using delayed-work for tty flip buffers ends up causing us to wait for
      the next tick to complete some actions.  That's usually not all that
      noticeable, but for certain latency-critical workloads it ends up being
      totally unacceptable.
      
      As an extreme case of this, passing a token back-and-forth over a pty
      will take two ticks per iteration, so even just a thousand iterations
      will take 8 seconds assuming a common 250Hz configuration.
      
      Avoiding the whole delayed work issue brings that ping-pong test-case
      down to 0.009s on my machine.
      
      In more practical terms, this latency has been a performance problem for
      things like dive computer simulators (simulating the serial interface
      using the ptys) and for other environments (Alan mentions a CP/M emulator).
      Reported-by: default avatarJef Driesen <jefdriesen@telenet.be>
      Acked-by: default avatarGreg KH <gregkh@suse.de>
      Acked-by: default avatarAlan Cox <alan@lxorguk.ukuu.org.uk>
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      f23eb2b2
  3. 09 Nov, 2010 1 commit
    • Jiri Olsa's avatar
      tty: prevent DOS in the flush_to_ldisc · e045fec4
      Jiri Olsa authored
      There's a small window inside the flush_to_ldisc function,
      where the tty is unlocked and calling ldisc's receive_buf
      function. If in this window new buffer is added to the tty,
      the processing might never leave the flush_to_ldisc function.
      
      This scenario will hog the cpu, causing other tty processing
      starving, and making it impossible to interface the computer
      via tty.
      
      I was able to exploit this via pty interface by sending only
      control characters to the master input, causing the flush_to_ldisc
      to be scheduled, but never actually generate any output.
      
      To reproduce, please run multiple instances of following code.
      
      - SNIP
      #define _XOPEN_SOURCE
      #include <stdlib.h>
      #include <stdio.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      
      int main(int argc, char **argv)
      {
              int i, slave, master = getpt();
              char buf[8192];
      
              sprintf(buf, "%s", ptsname(master));
              grantpt(master);
              unlockpt(master);
      
              slave = open(buf, O_RDWR);
              if (slave < 0) {
                      perror("open slave failed");
                      return 1;
              }
      
              for(i = 0; i < sizeof(buf); i++)
                      buf[i] = rand() % 32;
      
              while(1) {
                      write(master, buf, sizeof(buf));
              }
      
              return 0;
      }
      - SNIP
      
      The attached patch (based on -next tree) fixes this by checking on the
      tty buffer tail. Once it's reached, the current work is rescheduled
      and another could run.
      Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
      Cc: stable <stable@kernel.org>
      Acked-by: default avatarAlan Cox <alan@lxorguk.ukuu.org.uk>
      Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
      e045fec4
  4. 05 Nov, 2010 1 commit
  5. 21 May, 2010 1 commit
  6. 19 Mar, 2010 1 commit
    • Fang Wenqi's avatar
      tty_buffer: Fix distinct type warning · d4bee0a6
      Fang Wenqi authored
      CC      drivers/char/tty_buffer.o
      drivers/char/tty_buffer.c: In function ‘tty_insert_flip_string_fixed_flag’:
      drivers/char/tty_buffer.c:251: warning: comparison of distinct pointer types lacks a cast
      drivers/char/tty_buffer.c: In function ‘tty_insert_flip_string_flags’:
      drivers/char/tty_buffer.c:288: warning: comparison of distinct pointer types lacks a cast
      
      Fix it by replacing min() with min_t() in tty_insert_flip_string_flags and
      					  tty_insert_flip_string_fixed_flag().
      Signed-off-by: default avatarFang Wenqi <antonf@turbolinux.com.cn>
      Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
      d4bee0a6
  7. 02 Mar, 2010 2 commits
  8. 14 Oct, 2009 4 commits
    • Linus Torvalds's avatar
      tty: use the new 'flush_delayed_work()' helper to do ldisc flush · 97ad5a03
      Linus Torvalds authored
      This way all flush_to_ldisc work is always done through the workqueues,
      and we thus have a single point of serialization.  It also means that we
      can avoid calling flush_to_ldisc() entirely if there was no delayed work
      pending.
      
      [ Side note: using workqueues and keventd as the single way to enter
        flush_to_ldisc() still doesn't absolutely guarantee that we can't have
        concurrency: keventd is multithreaded and has a thread per CPU, and
        while the WORK_STRUCT_PENDING bit guarantees a single work only being
        on the pending list once, the work might be both pending and _running_
        at the same time. Workqueues are not simple. ]
      
      This was also confirmed to fix bugzilla #14388, even without the earlier
      locking fix and cleanup (commit c8e33141: "tty: Make flush_to_ldisc()
      locking more robust").  So both commits fix the same bug differently,
      and either would have worked on its own.  But I'm committing them both
      since they are cleanups independent of each other.
      Reported-and-tested-by: default avatarBoyan <btanastasov@yahoo.co.uk>
      Acked-by: default avatarAlan Cox <alan@lxorguk.ukuu.org.uk>
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      97ad5a03
    • Linus Torvalds's avatar
      tty: Make flush_to_ldisc() locking more robust · c8e33141
      Linus Torvalds authored
      The locking logic in this function is extremely subtle, and it broke
      when we started doing potentially concurrent 'flush_to_ldisc()' calls in
      commit e043e42b ("pty: avoid forcing
      'low_latency' tty flag").
      
      The code in flush_to_ldisc() used to set 'tty->buf.head' to NULL, with
      the intention that this would then cause any other concurrent calls to
      not do anything (locking note: we have to drop the buf.lock over the
      call to ->receive_buf that can block, which is why we can have
      concurrency here at all in the first place).
      
      It also used to set the TTY_FLUSHING bit, which would then cause any
      concurrent 'tty_buffer_flush()' to not free all the tty buffers and
      clear 'tty->buf.tail'.  And with 'buf.head' being NULL, and 'buf.tail'
      being non-NULL, new data would never touch 'buf.head'.
      
      Does that sound a bit too subtle? It was.  If another concurrent call to
      'flush_to_ldisc()' were to come in, the NULL buf.head would indeed cause
      it to not process the buffer list, but it would still clear TTY_FLUSHING
      afterwards, making the buffer protection against 'tty_buffer_flush()' no
      longer work.
      
      So this clears it all up.  We depend purely on TTY_FLUSHING for handling
      re-entrancy, and stop playing games with the buffer list entirely.  In
      fact, the buffer list handling is now robust enough that we could
      probably stop doing the whole "protect against 'tty_buffer_flush()'"
      thing entirely.
      
      However, Alan also points out that we would probably be better off
      simplifying the locking even further, and just take the tty ldisc_mutex
      around all the buffer flushing calls.  That seems like a good idea, but
      in the meantime this is a conceptually minimal fix (with the patch
      itself being bigger than required just to clean the code up and make it
      readable).
      
      This fixes keyboard trouble under X:
      
      	http://bugzilla.kernel.org/show_bug.cgi?id=14388Reported-and-tested-by: default avatarFrédéric Meunier <fredlwm@gmail.com>
      Reported-and-tested-by: default avatarBoyan <btanastasov@yahoo.co.uk>
      Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
      Cc: Paul Fulghum <paulkf@microgate.com>
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      c8e33141
    • Linus Torvalds's avatar
      tty: use the new 'flush_delayed_work()' helper to do ldisc flush · 514fc01d
      Linus Torvalds authored
      This way all flush_to_ldisc work is always done through the workqueues,
      and we thus have a single point of serialization.
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      514fc01d
    • Linus Torvalds's avatar
      45242006
  9. 29 Jul, 2009 1 commit
    • OGAWA Hirofumi's avatar
      pty: avoid forcing 'low_latency' tty flag · e043e42b
      OGAWA Hirofumi authored
      We really don't want to mark the pty as a low-latency device, because as
      Alan points out, the ->write method can be called from an IRQ (ppp?),
      and that means we can't use ->low_latency=1 as we take mutexes in the
      low_latency case.
      
      So rather than using low_latency to force the written data to be pushed
      to the ldisc handling at 'write()' time, just make the reader side (or
      the poll function) do the flush when it checks whether there is data to
      be had.
      
      This also fixes the problem with lost data in an emacs compile buffer
      (bugzilla 13815), and we can thus revert the low_latency pty hack
      (commit 3a542974: "pty: quickfix for the
      pty ENXIO timing problems").
      Signed-off-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
      Tested-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
      [ Modified to do the tty_flush_to_ldisc() inside input_available_p() so
        that it triggers for both read and poll()  - Linus]
      Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
      e043e42b
  10. 13 Oct, 2008 1 commit