|
@@ -582,6 +582,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|
|
|
|
|
tty_wait_until_sent(tty, 0);
|
|
tty_wait_until_sent(tty, 0);
|
|
|
|
|
|
|
|
+ tty_lock();
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -591,13 +592,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|
|
|
|
|
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
|
|
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
|
|
mutex_unlock(&tty->ldisc_mutex);
|
|
mutex_unlock(&tty->ldisc_mutex);
|
|
|
|
+ tty_unlock();
|
|
wait_event(tty_ldisc_wait,
|
|
wait_event(tty_ldisc_wait,
|
|
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
|
|
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
|
|
|
|
+ tty_lock();
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
}
|
|
}
|
|
|
|
|
|
- tty_lock();
|
|
|
|
-
|
|
|
|
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
|
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -634,8 +635,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
|
|
|
|
|
flush_scheduled_work();
|
|
flush_scheduled_work();
|
|
|
|
|
|
- mutex_lock(&tty->ldisc_mutex);
|
|
|
|
tty_lock();
|
|
tty_lock();
|
|
|
|
+ mutex_lock(&tty->ldisc_mutex);
|
|
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
|
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
|
/* We were raced by the hangup method. It will have stomped
|
|
/* We were raced by the hangup method. It will have stomped
|
|
the ldisc data and closed the ldisc down */
|
|
the ldisc data and closed the ldisc down */
|
|
@@ -782,7 +783,20 @@ void tty_ldisc_hangup(struct tty_struct *tty)
|
|
* Avoid racing set_ldisc or tty_ldisc_release
|
|
* Avoid racing set_ldisc or tty_ldisc_release
|
|
*/
|
|
*/
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
- tty_ldisc_halt(tty);
|
|
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * this is like tty_ldisc_halt, but we need to give up
|
|
|
|
+ * the BTM before calling cancel_delayed_work_sync,
|
|
|
|
+ * which may need to wait for another function taking the BTM
|
|
|
|
+ */
|
|
|
|
+ clear_bit(TTY_LDISC, &tty->flags);
|
|
|
|
+ tty_unlock();
|
|
|
|
+ cancel_delayed_work_sync(&tty->buf.work);
|
|
|
|
+ mutex_unlock(&tty->ldisc_mutex);
|
|
|
|
+
|
|
|
|
+ tty_lock();
|
|
|
|
+ mutex_lock(&tty->ldisc_mutex);
|
|
|
|
+
|
|
/* At this point we have a closed ldisc and we want to
|
|
/* At this point we have a closed ldisc and we want to
|
|
reopen it. We could defer this to the next open but
|
|
reopen it. We could defer this to the next open but
|
|
it means auditing a lot of other paths so this is
|
|
it means auditing a lot of other paths so this is
|
|
@@ -853,8 +867,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|
* race with the set_ldisc code path.
|
|
* race with the set_ldisc code path.
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
+ tty_unlock();
|
|
tty_ldisc_halt(tty);
|
|
tty_ldisc_halt(tty);
|
|
flush_scheduled_work();
|
|
flush_scheduled_work();
|
|
|
|
+ tty_lock();
|
|
|
|
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
mutex_lock(&tty->ldisc_mutex);
|
|
/*
|
|
/*
|