diff options
Diffstat (limited to 'drivers/tty/tty_ldisc.c')
-rw-r--r-- | drivers/tty/tty_ldisc.c | 30 |
1 files changed, 23 insertions, 7 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 512c49f98e85..8e0924f55446 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
@@ -36,6 +36,7 @@ | |||
36 | 36 | ||
37 | #include <linux/kmod.h> | 37 | #include <linux/kmod.h> |
38 | #include <linux/nsproxy.h> | 38 | #include <linux/nsproxy.h> |
39 | #include <linux/ratelimit.h> | ||
39 | 40 | ||
40 | /* | 41 | /* |
41 | * This guards the refcounted line discipline lists. The lock | 42 | * This guards the refcounted line discipline lists. The lock |
@@ -547,15 +548,16 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) | |||
547 | /** | 548 | /** |
548 | * tty_ldisc_wait_idle - wait for the ldisc to become idle | 549 | * tty_ldisc_wait_idle - wait for the ldisc to become idle |
549 | * @tty: tty to wait for | 550 | * @tty: tty to wait for |
551 | * @timeout: for how long to wait at most | ||
550 | * | 552 | * |
551 | * Wait for the line discipline to become idle. The discipline must | 553 | * Wait for the line discipline to become idle. The discipline must |
552 | * have been halted for this to guarantee it remains idle. | 554 | * have been halted for this to guarantee it remains idle. |
553 | */ | 555 | */ |
554 | static int tty_ldisc_wait_idle(struct tty_struct *tty) | 556 | static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) |
555 | { | 557 | { |
556 | int ret; | 558 | long ret; |
557 | ret = wait_event_timeout(tty_ldisc_idle, | 559 | ret = wait_event_timeout(tty_ldisc_idle, |
558 | atomic_read(&tty->ldisc->users) == 1, 5 * HZ); | 560 | atomic_read(&tty->ldisc->users) == 1, timeout); |
559 | if (ret < 0) | 561 | if (ret < 0) |
560 | return ret; | 562 | return ret; |
561 | return ret > 0 ? 0 : -EBUSY; | 563 | return ret > 0 ? 0 : -EBUSY; |
@@ -665,7 +667,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) | |||
665 | 667 | ||
666 | tty_ldisc_flush_works(tty); | 668 | tty_ldisc_flush_works(tty); |
667 | 669 | ||
668 | retval = tty_ldisc_wait_idle(tty); | 670 | retval = tty_ldisc_wait_idle(tty, 5 * HZ); |
669 | 671 | ||
670 | tty_lock(); | 672 | tty_lock(); |
671 | mutex_lock(&tty->ldisc_mutex); | 673 | mutex_lock(&tty->ldisc_mutex); |
@@ -762,8 +764,6 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) | |||
762 | if (IS_ERR(ld)) | 764 | if (IS_ERR(ld)) |
763 | return -1; | 765 | return -1; |
764 | 766 | ||
765 | WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); | ||
766 | |||
767 | tty_ldisc_close(tty, tty->ldisc); | 767 | tty_ldisc_close(tty, tty->ldisc); |
768 | tty_ldisc_put(tty->ldisc); | 768 | tty_ldisc_put(tty->ldisc); |
769 | tty->ldisc = NULL; | 769 | tty->ldisc = NULL; |
@@ -838,7 +838,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
838 | tty_unlock(); | 838 | tty_unlock(); |
839 | cancel_work_sync(&tty->buf.work); | 839 | cancel_work_sync(&tty->buf.work); |
840 | mutex_unlock(&tty->ldisc_mutex); | 840 | mutex_unlock(&tty->ldisc_mutex); |
841 | 841 | retry: | |
842 | tty_lock(); | 842 | tty_lock(); |
843 | mutex_lock(&tty->ldisc_mutex); | 843 | mutex_lock(&tty->ldisc_mutex); |
844 | 844 | ||
@@ -847,6 +847,22 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
847 | it means auditing a lot of other paths so this is | 847 | it means auditing a lot of other paths so this is |
848 | a FIXME */ | 848 | a FIXME */ |
849 | if (tty->ldisc) { /* Not yet closed */ | 849 | if (tty->ldisc) { /* Not yet closed */ |
850 | if (atomic_read(&tty->ldisc->users) != 1) { | ||
851 | char cur_n[TASK_COMM_LEN], tty_n[64]; | ||
852 | long timeout = 3 * HZ; | ||
853 | tty_unlock(); | ||
854 | |||
855 | while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { | ||
856 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
857 | printk_ratelimited(KERN_WARNING | ||
858 | "%s: waiting (%s) for %s took too long, but we keep waiting...\n", | ||
859 | __func__, get_task_comm(cur_n, current), | ||
860 | tty_name(tty, tty_n)); | ||
861 | } | ||
862 | mutex_unlock(&tty->ldisc_mutex); | ||
863 | goto retry; | ||
864 | } | ||
865 | |||
850 | if (reset == 0) { | 866 | if (reset == 0) { |
851 | 867 | ||
852 | if (!tty_ldisc_reinit(tty, tty->termios->c_line)) | 868 | if (!tty_ldisc_reinit(tty, tty->termios->c_line)) |