From df528eacaf4f626fb9ea05ff7ed250f79e58ae57 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Sun, 31 Oct 2010 23:17:51 +0100 Subject: [PATCH] --- yaml --- r: 221903 b: refs/heads/master c: 100eeae2c5ce23b4db93ff320ee330ef1d740151 h: refs/heads/master i: 221901: 1628de906865b68e208f40a887b2048cf7ac8c1c 221899: 8dea15e89b53374f65594f75e9e26d7e2b44d313 221895: c4ade9cae937739e6092f0b1fd48609244837795 221887: be681279e7bfbc0baa0ed300711c7070adee6f05 v: v3 --- [refs] | 2 +- trunk/drivers/tty/tty_ldisc.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index d795d45ed6e9..1876fbae37d0 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: ebf7c06635fbcf21a59e60187e166c5c23c57b06 +refs/heads/master: 100eeae2c5ce23b4db93ff320ee330ef1d740151 diff --git a/trunk/drivers/tty/tty_ldisc.c b/trunk/drivers/tty/tty_ldisc.c index 412f9775d19c..5bbf33ad49f1 100644 --- a/trunk/drivers/tty/tty_ldisc.c +++ b/trunk/drivers/tty/tty_ldisc.c @@ -47,6 +47,7 @@ static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); +static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_idle); /* Line disc dispatch table */ static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; @@ -83,6 +84,7 @@ static void put_ldisc(struct tty_ldisc *ld) return; } local_irq_restore(flags); + wake_up(&tty_ldisc_idle); } /** @@ -530,6 +532,23 @@ static int tty_ldisc_halt(struct tty_struct *tty) return cancel_delayed_work_sync(&tty->buf.work); } +/** + * tty_ldisc_wait_idle - wait for the ldisc to become idle + * @tty: tty to wait for + * + * Wait for the line discipline to become idle. The discipline must + * have been halted for this to guarantee it remains idle. + */ +static int tty_ldisc_wait_idle(struct tty_struct *tty) +{ + int ret; + ret = wait_event_interruptible_timeout(tty_ldisc_idle, + atomic_read(&tty->ldisc->users) == 1, 5 * HZ); + if (ret < 0) + return ret; + return ret > 0 ? 0 : -EBUSY; +} + /** * tty_set_ldisc - set line discipline * @tty: the terminal to set @@ -634,8 +653,17 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) flush_scheduled_work(); + retval = tty_ldisc_wait_idle(tty); + tty_lock(); mutex_lock(&tty->ldisc_mutex); + + /* handle wait idle failure locked */ + if (retval) { + tty_ldisc_put(new_ldisc); + goto enable; + } + if (test_bit(TTY_HUPPED, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ @@ -669,6 +697,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_ldisc_put(o_ldisc); +enable: /* * Allow ldisc referencing to occur again */