tty: make sure to flush any pending work when halting the ldisc
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Aug 2009 16:12:43 +0000 (09:12 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 25 Aug 2009 16:12:43 +0000 (09:12 -0700)
commit5c58ceff103d8a654f24769bb1baaf84a841b0cc
tree593c9f47c927850c7b2410c865d4c97aad9f2660
parent7111dc73923e9737b38a3ef5b5f236109000ff28
tty: make sure to flush any pending work when halting the ldisc

When I rewrote tty ldisc code to use proper reference counts (commits
65b770468e98 and cbe9352fa08f) in order to avoid a race with hangup, the
test-program that Eric Biederman used to trigger the original problem
seems to have exposed another long-standing bug: the hangup code did the
'tty_ldisc_halt()' to stop any buffer flushing activity, but unlike the
other call sites it never actually flushed any pending work.

As a result, if you get just the right timing, the pending work may be
just about to execute (ie the timer has already triggered and thus
cancel_delayed_work() was a no-op), when we then re-initialize the ldisc
from under it.

That, in turn, results in various random problems, usually seen as a
NULL pointer dereference in run_timer_softirq() or a BUG() in
worker_thread (but it can be almost anything).

Fix it by adding the required 'flush_scheduled_work()' after doing the
tty_ldisc_halt() (this also requires us to move the ldisc halt to before
taking the ldisc mutex in order to avoid a deadlock with the workqueue
executing do_tty_hangup, which requires the mutex).

The locking should be cleaned up one day (the requirement to do this
outside the ldisc_mutex is very annoying, and weakens the lock), but
that's a larger and separate undertaking.

Reported-by: Eric W. Biederman <ebiederm@xmission.com>
Tested-by: Xiaotian Feng <xtfeng@gmail.com>
Tested-by: Yanmin Zhang <yanmin_zhang@linux.intel.com>
Tested-by: Dave Young <hidave.darkstar@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/char/tty_ldisc.c