diff options
author | Jiri Slaby <jslaby@suse.cz> | 2012-10-18 22:26:33 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-10-22 16:50:53 -0700 |
commit | 31e121284f90bf559618330e230b286f969b6b7f (patch) | |
tree | 8a1f6e5016c0dc60374f512d56769e0793b6250b /drivers/tty | |
parent | 7ee00fdb16418dd5078ec73e4a631c278a366501 (diff) |
TTY: ldisc, wait for idle ldisc in release
We reintroduced tty_ldisc_wait_idle in 100eeae2c5c (TTY: restore
tty_ldisc_wait_idle) and used in set_ldisc. Then we added it also to
the hangup path in 92f6fa09bd453 (TTY: ldisc, do not close until there
are readers). And we noted that there is one more path:
~ Before 65b770468e98 tty_ldisc_wait_idle was called also from
~ tty_ldisc_release. It is called from tty_release, so I don't think
~ we need to restore that one.
Well, I was wrong. There might still be holders of an ldisc
reference. Not from userspace, but drivers. If they take a reference
and a user closes the device immediately after that, we have a
problem. ldisc is halted and closed by TTY, but the driver still may
call some ldisc's operation and cause a crash.
So restore the tty_ldisc_wait_idle call also to the third location
where it was before 65b770468e98 (tty-ldisc: turn ldisc user count
into a proper refcount). Now we should be safe with respect to the
ldisc reference counting as all* tty_ldisc_close paths are safely
called with reference count of one.
* Not the one in tty_ldisc_setup's fail path. But that is called
before the first open finishes. So userspace does not see it yet.
Even thought the driver is given the TTY already via ->install, it
should not take a reference to the ldisc yet. If some driver is to
do this, we should put one tty_ldisc_wait_idle also in the setup.
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Acked-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r-- | drivers/tty/tty_ldisc.c | 5 |
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 0f2a2c5e704c..47e3968df10b 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -897,6 +897,11 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) static void tty_ldisc_kill(struct tty_struct *tty) { + /* There cannot be users from userspace now. But there still might be + * drivers holding a reference via tty_ldisc_ref. Do not steal them the + * ldisc until they are done. */ + tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT); + mutex_lock(&tty->ldisc_mutex); /* * Now kill off the ldisc |