05 Dec, 2018

1 commit

  • There might be situations where tty_ldisc_lock() has blocked, but there
    is already IO on tty and it prevents line discipline changes.
    It might theoretically turn into dead-lock.

    Basically, provide more priority to pending tty_ldisc_lock() than to
    servicing reads/writes over tty.

    User-visible issue was reported by Mikulas where on pa-risc with
    Debian 5 reboot took either 80 seconds, 3 minutes or 3:25 after proper
    locking in tty_reopen().

    Cc: Jiri Slaby
    Reported-by: Mikulas Patocka
    Signed-off-by: Dmitry Safonov
    Signed-off-by: Greg Kroah-Hartman

    Dmitry Safonov
     

13 Oct, 2018

1 commit

  • First of all, make it return int. Returning long when native method
    had never allowed that is ridiculous and inconvenient.

    More importantly, change the caller; if ldisc ->compat_ioctl() is NULL
    or returns -ENOIOCTLCMD, tty_compat_ioctl() will try to feed cmd and
    compat_ptr(arg) to ldisc's native ->ioctl().

    That simplifies ->compat_ioctl() instances quite a bit - they only
    need to deal with ioctls that are neither generic tty ones (those
    would get shunted off to tty_ioctl()) nor simple compat pointer ones.

    Note that something like TCFLSH won't reach ->compat_ioctl(),
    even if ldisc ->ioctl() does handle it - it will be recognized
    earlier and passed to tty_ioctl() (and ultimately - ldisc ->ioctl()).

    For many ldiscs it means that NULL ->compat_ioctl() does the
    right thing. Those where it won't serve (see e.g. n_r3964.c) are
    also easily dealt with - we need to handle the numeric-argument
    ioctls (calling the native instance) and, if such would exist,
    the ioctls that need layout conversion, etc.

    All in-tree ldiscs dealt with.

    Signed-off-by: Al Viro

    Al Viro
     

12 Feb, 2018

1 commit

  • 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/^\([^\"]*\)\(\\)/\\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: Al Viro
    Signed-off-by: Linus Torvalds

    Linus Torvalds
     

29 Nov, 2017

1 commit


22 Nov, 2017

1 commit

  • This converts all remaining cases of the old setup_timer() API into using
    timer_setup(), where the callback argument is the structure already
    holding the struct timer_list. These should have no behavioral changes,
    since they just change which pointer is passed into the callback with
    the same available pointers after conversion. It handles the following
    examples, in addition to some other variations.

    Casting from unsigned long:

    void my_callback(unsigned long data)
    {
    struct something *ptr = (struct something *)data;
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, ptr);

    and forced object casts:

    void my_callback(struct something *ptr)
    {
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);

    become:

    void my_callback(struct timer_list *t)
    {
    struct something *ptr = from_timer(ptr, t, my_timer);
    ...
    }
    ...
    timer_setup(&ptr->my_timer, my_callback, 0);

    Direct function assignments:

    void my_callback(unsigned long data)
    {
    struct something *ptr = (struct something *)data;
    ...
    }
    ...
    ptr->my_timer.function = my_callback;

    have a temporary cast added, along with converting the args:

    void my_callback(struct timer_list *t)
    {
    struct something *ptr = from_timer(ptr, t, my_timer);
    ...
    }
    ...
    ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;

    And finally, callbacks without a data assignment:

    void my_callback(unsigned long data)
    {
    ...
    }
    ...
    setup_timer(&ptr->my_timer, my_callback, 0);

    have their argument renamed to verify they're unused during conversion:

    void my_callback(struct timer_list *unused)
    {
    ...
    }
    ...
    timer_setup(&ptr->my_timer, my_callback, 0);

    The conversion is done with the following Coccinelle script:

    spatch --very-quiet --all-includes --include-headers \
    -I ./arch/x86/include -I ./arch/x86/include/generated \
    -I ./include -I ./arch/x86/include/uapi \
    -I ./arch/x86/include/generated/uapi -I ./include/uapi \
    -I ./include/generated/uapi --include ./include/linux/kconfig.h \
    --dir . \
    --cocci-file ~/src/data/timer_setup.cocci

    @fix_address_of@
    expression e;
    @@

    setup_timer(
    -&(e)
    +&e
    , ...)

    // Update any raw setup_timer() usages that have a NULL callback, but
    // would otherwise match change_timer_function_usage, since the latter
    // will update all function assignments done in the face of a NULL
    // function initialization in setup_timer().
    @change_timer_function_usage_NULL@
    expression _E;
    identifier _timer;
    type _cast_data;
    @@

    (
    -setup_timer(&_E->_timer, NULL, _E);
    +timer_setup(&_E->_timer, NULL, 0);
    |
    -setup_timer(&_E->_timer, NULL, (_cast_data)_E);
    +timer_setup(&_E->_timer, NULL, 0);
    |
    -setup_timer(&_E._timer, NULL, &_E);
    +timer_setup(&_E._timer, NULL, 0);
    |
    -setup_timer(&_E._timer, NULL, (_cast_data)&_E);
    +timer_setup(&_E._timer, NULL, 0);
    )

    @change_timer_function_usage@
    expression _E;
    identifier _timer;
    struct timer_list _stl;
    identifier _callback;
    type _cast_func, _cast_data;
    @@

    (
    -setup_timer(&_E->_timer, _callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, &_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, &_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
    +timer_setup(&_E._timer, _callback, 0);
    |
    _E->_timer@_stl.function = _callback;
    |
    _E->_timer@_stl.function = &_callback;
    |
    _E->_timer@_stl.function = (_cast_func)_callback;
    |
    _E->_timer@_stl.function = (_cast_func)&_callback;
    |
    _E._timer@_stl.function = _callback;
    |
    _E._timer@_stl.function = &_callback;
    |
    _E._timer@_stl.function = (_cast_func)_callback;
    |
    _E._timer@_stl.function = (_cast_func)&_callback;
    )

    // callback(unsigned long arg)
    @change_callback_handle_cast
    depends on change_timer_function_usage@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _origtype;
    identifier _origarg;
    type _handletype;
    identifier _handle;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *t
    )
    {
    (
    ... when != _origarg
    _handletype *_handle =
    -(_handletype *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle =
    -(void *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle;
    ... when != _handle
    _handle =
    -(_handletype *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    |
    ... when != _origarg
    _handletype *_handle;
    ... when != _handle
    _handle =
    -(void *)_origarg;
    +from_timer(_handle, t, _timer);
    ... when != _origarg
    )
    }

    // callback(unsigned long arg) without existing variable
    @change_callback_handle_cast_no_arg
    depends on change_timer_function_usage &&
    !change_callback_handle_cast@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _origtype;
    identifier _origarg;
    type _handletype;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *t
    )
    {
    + _handletype *_origarg = from_timer(_origarg, t, _timer);
    +
    ... when != _origarg
    - (_handletype *)_origarg
    + _origarg
    ... when != _origarg
    }

    // Avoid already converted callbacks.
    @match_callback_converted
    depends on change_timer_function_usage &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg@
    identifier change_timer_function_usage._callback;
    identifier t;
    @@

    void _callback(struct timer_list *t)
    { ... }

    // callback(struct something *handle)
    @change_callback_handle_arg
    depends on change_timer_function_usage &&
    !match_callback_converted &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _handletype;
    identifier _handle;
    @@

    void _callback(
    -_handletype *_handle
    +struct timer_list *t
    )
    {
    + _handletype *_handle = from_timer(_handle, t, _timer);
    ...
    }

    // If change_callback_handle_arg ran on an empty function, remove
    // the added handler.
    @unchange_callback_handle_arg
    depends on change_timer_function_usage &&
    change_callback_handle_arg@
    identifier change_timer_function_usage._callback;
    identifier change_timer_function_usage._timer;
    type _handletype;
    identifier _handle;
    identifier t;
    @@

    void _callback(struct timer_list *t)
    {
    - _handletype *_handle = from_timer(_handle, t, _timer);
    }

    // We only want to refactor the setup_timer() data argument if we've found
    // the matching callback. This undoes changes in change_timer_function_usage.
    @unchange_timer_function_usage
    depends on change_timer_function_usage &&
    !change_callback_handle_cast &&
    !change_callback_handle_cast_no_arg &&
    !change_callback_handle_arg@
    expression change_timer_function_usage._E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type change_timer_function_usage._cast_data;
    @@

    (
    -timer_setup(&_E->_timer, _callback, 0);
    +setup_timer(&_E->_timer, _callback, (_cast_data)_E);
    |
    -timer_setup(&_E._timer, _callback, 0);
    +setup_timer(&_E._timer, _callback, (_cast_data)&_E);
    )

    // If we fixed a callback from a .function assignment, fix the
    // assignment cast now.
    @change_timer_function_assignment
    depends on change_timer_function_usage &&
    (change_callback_handle_cast ||
    change_callback_handle_cast_no_arg ||
    change_callback_handle_arg)@
    expression change_timer_function_usage._E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type _cast_func;
    typedef TIMER_FUNC_TYPE;
    @@

    (
    _E->_timer.function =
    -_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -(_cast_func)_callback;
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E->_timer.function =
    -(_cast_func)&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -&_callback;
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -(_cast_func)_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    |
    _E._timer.function =
    -(_cast_func)&_callback
    +(TIMER_FUNC_TYPE)_callback
    ;
    )

    // Sometimes timer functions are called directly. Replace matched args.
    @change_timer_function_calls
    depends on change_timer_function_usage &&
    (change_callback_handle_cast ||
    change_callback_handle_cast_no_arg ||
    change_callback_handle_arg)@
    expression _E;
    identifier change_timer_function_usage._timer;
    identifier change_timer_function_usage._callback;
    type _cast_data;
    @@

    _callback(
    (
    -(_cast_data)_E
    +&_E->_timer
    |
    -(_cast_data)&_E
    +&_E._timer
    |
    -_E
    +&_E->_timer
    )
    )

    // If a timer has been configured without a data argument, it can be
    // converted without regard to the callback argument, since it is unused.
    @match_timer_function_unused_data@
    expression _E;
    identifier _timer;
    identifier _callback;
    @@

    (
    -setup_timer(&_E->_timer, _callback, 0);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, 0L);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E->_timer, _callback, 0UL);
    +timer_setup(&_E->_timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0L);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_E._timer, _callback, 0UL);
    +timer_setup(&_E._timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0L);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(&_timer, _callback, 0UL);
    +timer_setup(&_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0);
    +timer_setup(_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0L);
    +timer_setup(_timer, _callback, 0);
    |
    -setup_timer(_timer, _callback, 0UL);
    +timer_setup(_timer, _callback, 0);
    )

    @change_callback_unused_data
    depends on match_timer_function_unused_data@
    identifier match_timer_function_unused_data._callback;
    type _origtype;
    identifier _origarg;
    @@

    void _callback(
    -_origtype _origarg
    +struct timer_list *unused
    )
    {
    ... when != _origarg
    }

    Signed-off-by: Kees Cook

    Kees Cook
     

08 Nov, 2017

2 commits

  • 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
    Cc: James Hogan
    Signed-off-by: Greg Kroah-Hartman

    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
    Cc: Benjamin Herrenschmidt
    Cc: Paul Mackerras
    Cc: Michael Ellerman
    Cc: Chris Metcalf
    Cc: Jiri Kosina
    Cc: David Sterba
    Cc: James Hogan
    Cc: Rob Herring
    Cc: Eric Anholt
    Cc: Stefan Wahren
    Cc: Florian Fainelli
    Cc: Ray Jui
    Cc: Scott Branden
    Cc: bcm-kernel-feedback-list@broadcom.com
    Cc: "James E.J. Bottomley"
    Cc: Helge Deller
    Cc: Joachim Eastwood
    Cc: Matthias Brugger
    Cc: Masahiro Yamada
    Cc: Tobias Klauser
    Cc: Russell King
    Cc: Vineet Gupta
    Cc: Richard Genoud
    Cc: Alexander Shiyan
    Cc: Baruch Siach
    Cc: "Maciej W. Rozycki"
    Cc: "Uwe Kleine-König"
    Cc: Pat Gefre
    Cc: "Guilherme G. Piccoli"
    Cc: Jason Wessel
    Cc: Vladimir Zapolskiy
    Cc: Sylvain Lemieux
    Cc: Carlo Caione
    Cc: Kevin Hilman
    Cc: Liviu Dudau
    Cc: Sudeep Holla
    Cc: Lorenzo Pieralisi
    Cc: Andy Gross
    Cc: David Brown
    Cc: "Andreas Färber"
    Cc: Kevin Cernekee
    Cc: Laxman Dewangan
    Cc: Thierry Reding
    Cc: Jonathan Hunter
    Cc: Barry Song
    Cc: Patrice Chotard
    Cc: Maxime Coquelin
    Cc: Alexandre Torgue
    Cc: "David S. Miller"
    Cc: Peter Korsgaard
    Cc: Timur Tabi
    Cc: Tony Prisk
    Cc: Michal Simek
    Cc: "Sören Brinkmann"
    Cc: Thomas Gleixner
    Cc: Kate Stewart
    Cc: Philippe Ombredanne
    Cc: Jiri Slaby
    Signed-off-by: Greg Kroah-Hartman

    Greg Kroah-Hartman
     

25 Dec, 2016

1 commit


18 Oct, 2015

2 commits

  • The tty lock is strictly for serializing tty lifetime events
    (open/close/hangup), and not for line discipline serialization.

    The tty core already provides serialization of concurrent writes
    to the same tty, and line discipline lifetime management (by ldisc
    references), so pinning the tty via tty_lock() is unnecessary and
    counter-productive; remove tty lock use.

    However, the line discipline is responsible for serializing reads
    (if required by the line discipline); add read_lock mutex to
    serialize calls of r3964_read().

    Signed-off-by: Peter Hurley
    Signed-off-by: Greg Kroah-Hartman

    Peter Hurley
     
  • The tty core provides read_wait waitqueue specifically for line
    disciplines to wait readers; otherwise, the line discipline may
    miss wakeups generated by the tty core.

    NB: The tty core already provides serialization for the line discipline's
    close() method, and guarantees no readers or writers will be using the
    closing instance of the line discipline. Completely remove that wakeup.

    Signed-off-by: Peter Hurley
    Signed-off-by: Greg Kroah-Hartman

    Peter Hurley
     

09 Dec, 2013

1 commit

  • Most line disciplines already handle the undocumented NULL flag
    ptr in their .receive_buf method; however, several don't.

    Document the NULL flag ptr, and correct handling in the
    N_MOUSE, N_GSM0710 and N_R394 line disciplines.

    Signed-off-by: Peter Hurley
    Acked-by: Dmitry Torokhov
    Signed-off-by: Greg Kroah-Hartman

    Peter Hurley
     

11 Aug, 2012

1 commit

  • The termios and other changes mean the other protections needed on the driver
    tty arrays should be adequate. Turn it all back on.

    This contains pieces folded in from the fixes made to the original patches

    | From: Geert Uytterhoeven (fix m68k)
    | From: Paul Gortmaker (fix cris)
    | From: Jiri Kosina (lockdep)
    | From: Eric Dumazet (lockdep)

    Signed-off-by: Alan Cox
    Signed-off-by: Greg Kroah-Hartman

    Alan Cox
     

17 Jul, 2012

1 commit

  • I sent GregKH this after the pre-requisites. He dropped the pre-requesites
    for good reason and unfortunately then applied this patch. Without this
    reverted you get random kernel memory corruption which will make bisecting
    anything between it and the properly applied patches a complete sod.

    Signed-off-by: Alan Cox
    Signed-off-by: Greg Kroah-Hartman

    Alan Cox
     

07 Jul, 2012

1 commit

  • The termios and other changes mean the other protections needed on the driver
    tty arrays should be adequate. Turn it all back on.

    This contains pieces folded in from the fixes made to the original patches

    | From: Geert Uytterhoeven (fix m68k)
    | From: Paul Gortmaker (fix cris)
    | From: Jiri Kosina (lockdep)
    | From: Eric Dumazet (lockdep)

    Signed-off-by: Alan Cox
    Signed-off-by: Greg Kroah-Hartman

    Alan Cox
     

03 Jun, 2012

1 commit

  • This reverts the tty layer change to use per-tty locking, because it's
    not correct yet, and fixing it will require some more deep surgery.

    The main revert is d29f3ef39be4 ("tty_lock: Localise the lock"), but
    there are several smaller commits that built upon it, they also get
    reverted here. The list of reverted commits is:

    fde86d310886 - tty: add lockdep annotations
    8f6576ad476b - tty: fix ldisc lock inversion trace
    d3ca8b64b97e - pty: Fix lock inversion
    b1d679afd766 - tty: drop the pty lock during hangup
    abcefe5fc357 - tty/amiserial: Add missing argument for tty_unlock()
    fd11b42e3598 - cris: fix missing tty arg in wait_event_interruptible_tty call
    d29f3ef39be4 - tty_lock: Localise the lock

    The revert had a trivial conflict in the 68360serial.c staging driver
    that got removed in the meantime.

    Signed-off-by: Linus Torvalds

    Linus Torvalds
     

05 May, 2012

1 commit

  • In each remaining case the tty_lock is associated with a specific tty. This
    means we can now lock on a per tty basis. We do need tty_lock_pair() for
    the pty case. Uglier but still a step in the right direction.

    [fixed up calls in 3 missing drivers - gregkh]

    Signed-off-by: Alan Cox
    Acked-by: Arnd Bergmann
    Signed-off-by: Greg Kroah-Hartman

    Alan Cox
     

04 Jun, 2011

1 commit

  • This reverts commit b1c43f82c5aa265442f82dba31ce985ebb7aa71c.

    It was broken in so many ways, and results in random odd pty issues.

    It re-introduced the buggy schedule_work() in flush_to_ldisc() that can
    cause endless work-loops (see commit a5660b41af6a: "tty: fix endless
    work loop when the buffer fills up").

    It also used an "unsigned int" return value fo the ->receive_buf()
    function, but then made multiple functions return a negative error code,
    and didn't actually check for the error in the caller.

    And it didn't actually work at all. BenH bisected down odd tty behavior
    to it:
    "It looks like the patch is causing some major malfunctions of the X
    server for me, possibly related to PTYs. For example, cat'ing a
    large file in a gnome terminal hangs the kernel for -minutes- in a
    loop of what looks like flush_to_ldisc/workqueue code, (some ftrace
    data in the quoted bits further down).

    ...

    Some more data: It -looks- like what happens is that the
    flush_to_ldisc work queue entry constantly re-queues itself (because
    the PTY is full ?) and the workqueue thread will basically loop
    forver calling it without ever scheduling, thus starving the consumer
    process that could have emptied the PTY."

    which is pretty much exactly the problem we fixed in a5660b41af6a.

    Milton Miller pointed out the 'unsigned int' issue.

    Reported-by: Benjamin Herrenschmidt
    Reported-by: Milton Miller
    Cc: Stefan Bigler
    Cc: Toby Gray
    Cc: Felipe Balbi
    Cc: Greg Kroah-Hartman
    Cc: Alan Cox
    Signed-off-by: Linus Torvalds

    Linus Torvalds
     

23 Apr, 2011

1 commit

  • it makes it simpler to keep track of the amount of
    bytes received and simplifies how flush_to_ldisc counts
    the remaining bytes. It also fixes a bug of lost bytes
    on n_tty when flushing too many bytes via the USB
    serial gadget driver.

    Tested-by: Stefan Bigler
    Tested-by: Toby Gray
    Signed-off-by: Felipe Balbi
    Signed-off-by: Greg Kroah-Hartman

    Felipe Balbi
     

02 Mar, 2011

1 commit


05 Nov, 2010

1 commit