浏览代码

tty: Fix timeout on pty set ldisc

When changing the ldisc on one end of a pty pair, there may be
waiting readers/writers on the other end which may not exit from
the ldisc i/o loop, preventing tty_ldisc_lock_pair_timeout() from
acquiring the other side's ldisc lock.

Only acquire this side's ldisc lock; although this will no longer
prevent the other side from writing new input, that input will not
be processed until after the ldisc change completes. This has no
effect on normal ttys; new input from the driver was never disabled.

Remove tty_ldisc_enable_pair().

Reviewed-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Peter Hurley 11 年之前
父节点
当前提交
276a661a4d
共有 1 个文件被更改,包括 4 次插入17 次删除
  1. 4 17
      drivers/tty/tty_ldisc.c

+ 4 - 17
drivers/tty/tty_ldisc.c

@@ -393,16 +393,6 @@ static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
 		__tty_ldisc_unlock(tty2);
 		__tty_ldisc_unlock(tty2);
 }
 }
 
 
-static void __lockfunc tty_ldisc_enable_pair(struct tty_struct *tty,
-					     struct tty_struct *tty2)
-{
-	clear_bit(TTY_LDISC_HALTED, &tty->flags);
-	if (tty2)
-		clear_bit(TTY_LDISC_HALTED, &tty2->flags);
-
-	tty_ldisc_unlock_pair(tty, tty2);
-}
-
 /**
 /**
  *	tty_ldisc_flush	-	flush line discipline queue
  *	tty_ldisc_flush	-	flush line discipline queue
  *	@tty: tty
  *	@tty: tty
@@ -535,14 +525,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 {
 {
 	int retval;
 	int retval;
 	struct tty_ldisc *old_ldisc, *new_ldisc;
 	struct tty_ldisc *old_ldisc, *new_ldisc;
-	struct tty_struct *o_tty = tty->link;
 
 
 	new_ldisc = tty_ldisc_get(tty, ldisc);
 	new_ldisc = tty_ldisc_get(tty, ldisc);
 	if (IS_ERR(new_ldisc))
 	if (IS_ERR(new_ldisc))
 		return PTR_ERR(new_ldisc);
 		return PTR_ERR(new_ldisc);
 
 
 	tty_lock(tty);
 	tty_lock(tty);
-	retval = tty_ldisc_lock_pair_timeout(tty, o_tty, 5 * HZ);
+	retval = tty_ldisc_lock(tty, 5 * HZ);
 	if (retval) {
 	if (retval) {
 		tty_ldisc_put(new_ldisc);
 		tty_ldisc_put(new_ldisc);
 		tty_unlock(tty);
 		tty_unlock(tty);
@@ -554,7 +543,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	 */
 	 */
 
 
 	if (tty->ldisc->ops->num == ldisc) {
 	if (tty->ldisc->ops->num == ldisc) {
-		tty_ldisc_enable_pair(tty, o_tty);
+		tty_ldisc_unlock(tty);
 		tty_ldisc_put(new_ldisc);
 		tty_ldisc_put(new_ldisc);
 		tty_unlock(tty);
 		tty_unlock(tty);
 		return 0;
 		return 0;
@@ -565,7 +554,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	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 */
-		tty_ldisc_enable_pair(tty, o_tty);
+		tty_ldisc_unlock(tty);
 		tty_ldisc_put(new_ldisc);
 		tty_ldisc_put(new_ldisc);
 		tty_unlock(tty);
 		tty_unlock(tty);
 		return -EIO;
 		return -EIO;
@@ -599,13 +588,11 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	/*
 	/*
 	 *	Allow ldisc referencing to occur again
 	 *	Allow ldisc referencing to occur again
 	 */
 	 */
-	tty_ldisc_enable_pair(tty, o_tty);
+	tty_ldisc_unlock(tty);
 
 
 	/* Restart the work queue in case no characters kick it off. Safe if
 	/* Restart the work queue in case no characters kick it off. Safe if
 	   already running */
 	   already running */
 	schedule_work(&tty->port->buf.work);
 	schedule_work(&tty->port->buf.work);
-	if (o_tty)
-		schedule_work(&o_tty->port->buf.work);
 
 
 	tty_unlock(tty);
 	tty_unlock(tty);
 	return retval;
 	return retval;