| From 15490ab9d58994558ce5de0116c20fc8ac32f68f Mon Sep 17 00:00:00 2001 |
| From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| Date: Fri, 11 Oct 2013 16:15:08 +0200 |
| Subject: [PATCH] tty: ldisc: drop the raw lock earlier |
| |
| Luis Claudio R. Goncalves reported the following: |
| |
| |BUG: sleeping function called from invalid context at kernel/rtmutex.c:659 |
| |in_atomic(): 1, irqs_disabled(): 1, pid: 188, name: plymouthd |
| |3 locks held by plymouthd/188: |
| | #0: (&tty->legacy_mutex){......}, at: [<ffffffff816528d0>] tty_lock_nested+0x40/0x90 |
| | #1: (&tty->ldisc_mutex){......}, at: [<ffffffff8139b482>] tty_ldisc_hangup+0x152/0x300 |
| | #2: (tty_ldisc_lock){......}, at: [<ffffffff8139a9c2>] tty_ldisc_reinit+0x72/0x130 |
| |Preemption disabled at:[<ffffffff8139a9c2>] tty_ldisc_reinit+0x72/0x130 |
| |CPU: 2 PID: 188 Comm: plymouthd Not tainted 3.10.10-rt7+ #6 |
| |Call Trace: |
| | [<ffffffff8164b790>] dump_stack+0x19/0x1b |
| | [<ffffffff8107e62f>] __might_sleep+0xff/0x170 |
| | [<ffffffff81651ac4>] rt_spin_lock+0x24/0x60 |
| | [<ffffffff81130984>] free_hot_cold_page+0xb4/0x3c0 |
| | [<ffffffff81178209>] ?unfreeze_partials.isra.42+0x229/0x2b0 |
| | [<ffffffff81130dc7>] __free_pages+0x47/0x70 |
| | [<ffffffff81130fb2>] __free_memcg_kmem_pages+0x22/0x50 |
| | [<ffffffff81177528>] __free_slab+0xe8/0x1e0 |
| | [<ffffffff81177654>] free_delayed+0x34/0x50 |
| | [<ffffffff81649633>] __slab_free+0x273/0x36b |
| | [<ffffffff81178794>] kfree+0x1c4/0x210 |
| | [<ffffffff8139a9f5>] tty_ldisc_reinit+0xa5/0x130 |
| | [<ffffffff8139b49f>] tty_ldisc_hangup+0x16f/0x300 |
| | [<ffffffff81392136>] __tty_hangup+0x346/0x460 |
| | [<ffffffff81392260>] tty_vhangup+0x10/0x20 |
| | [<ffffffff8139d6e1>] pty_close+0x131/0x180 |
| | [<ffffffff813936ad>] tty_release+0x11d/0x5f0 |
| |
| It looks safe to drop the tty_ldisc_lock lock before module_put() and |
| kree() so do it. |
| |
| Cc: stable-rt@vger.kernel.org |
| Reported-By: Luis Claudio R. Goncalves <lclaudio@uudg.org> |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| drivers/tty/tty_ldisc.c | 3 ++- |
| 1 file changed, 2 insertions(+), 1 deletion(-) |
| |
| diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c |
| index 1afe192..bc4ffe4 100644 |
| --- a/drivers/tty/tty_ldisc.c |
| +++ b/drivers/tty/tty_ldisc.c |
| @@ -197,9 +197,10 @@ static inline void tty_ldisc_put(struct tty_ldisc *ld) |
| WARN_ON(!atomic_dec_and_test(&ld->users)); |
| |
| ld->ops->refcount--; |
| + raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
| + |
| module_put(ld->ops->owner); |
| kfree(ld); |
| - raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
| } |
| |
| static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) |
| -- |
| 1.8.4.rc3 |
| |