• Linus Torvalds's avatar
    tty: Make flush_to_ldisc() locking more robust · 86d23a05
    Linus Torvalds authored
    commit c8e33141 upstream.
    
    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>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
    86d23a05
tty_buffer.c 13.6 KB