Browse Source

tty: Simplify tty_set_ldisc() exit handling

Perform common exit for both successful and error exit handling
in tty_set_ldisc(). Fixes unlikely possibility of failing to restart
input kworker when switching to the same line discipline (noop case).

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Peter Hurley 9 years ago
parent
commit
63d8cb3f19
1 changed files with 13 additions and 29 deletions
  1. 13 29
      drivers/tty/tty_ldisc.c

+ 13 - 29
drivers/tty/tty_ldisc.c

@@ -529,34 +529,21 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 
 
 	tty_lock(tty);
 	tty_lock(tty);
 	retval = tty_ldisc_lock(tty, 5 * HZ);
 	retval = tty_ldisc_lock(tty, 5 * HZ);
-	if (retval) {
-		tty_ldisc_put(new_ldisc);
-		tty_unlock(tty);
-		return retval;
-	}
+	if (retval)
+		goto err;
 
 
-	/*
-	 *	Check the no-op case
-	 */
+	/* Check the no-op case */
+	if (tty->ldisc->ops->num == ldisc)
+		goto out;
 
 
-	if (tty->ldisc->ops->num == ldisc) {
-		tty_ldisc_unlock(tty);
-		tty_ldisc_put(new_ldisc);
-		tty_unlock(tty);
-		return 0;
+	if (test_bit(TTY_HUPPED, &tty->flags)) {
+		/* We were raced by hangup */
+		retval = -EIO;
+		goto out;
 	}
 	}
 
 
 	old_ldisc = tty->ldisc;
 	old_ldisc = tty->ldisc;
 
 
-	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 */
-		tty_ldisc_unlock(tty);
-		tty_ldisc_put(new_ldisc);
-		tty_unlock(tty);
-		return -EIO;
-	}
-
 	/* Shutdown the old discipline. */
 	/* Shutdown the old discipline. */
 	tty_ldisc_close(tty, old_ldisc);
 	tty_ldisc_close(tty, old_ldisc);
 
 
@@ -582,18 +569,15 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
 	   the old ldisc (if it was restored as part of error cleanup
 	   the old ldisc (if it was restored as part of error cleanup
 	   above). In either case, releasing a single reference from
 	   above). In either case, releasing a single reference from
 	   the old ldisc is correct. */
 	   the old ldisc is correct. */
-
-	tty_ldisc_put(old_ldisc);
-
-	/*
-	 *	Allow ldisc referencing to occur again
-	 */
+	new_ldisc = old_ldisc;
+out:
 	tty_ldisc_unlock(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 */
 	tty_buffer_restart_work(tty->port);
 	tty_buffer_restart_work(tty->port);
-
+err:
+	tty_ldisc_put(new_ldisc);	/* drop the extra reference */
 	tty_unlock(tty);
 	tty_unlock(tty);
 	return retval;
 	return retval;
 }
 }