Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c9b3976e authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds
Browse files

tty: Fix PPP hang under load

parent d0eafc7d
Loading
Loading
Loading
Loading
+21 −9
Original line number Diff line number Diff line
@@ -316,8 +316,7 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
	/* wait_event is a macro */
	wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
	if (tty->ldisc.refcount == 0)
		printk(KERN_ERR "tty_ldisc_ref_wait\n");
	WARN_ON(tty->ldisc.refcount == 0);
	return &tty->ldisc;
}

@@ -376,15 +375,17 @@ EXPORT_SYMBOL_GPL(tty_ldisc_deref);
 *	@tty: terminal to activate ldisc on
 *
 *	Set the TTY_LDISC flag when the line discipline can be called
 *	again. Do necessary wakeups for existing sleepers.
 *	again. Do necessary wakeups for existing sleepers. Clear the LDISC
 *	changing flag to indicate any ldisc change is now over.
 *
 *	Note: nobody should set this bit except via this function. Clearing
 *	directly is allowed.
 *	Note: nobody should set the TTY_LDISC bit except via this function.
 *	Clearing directly is allowed.
 */

void tty_ldisc_enable(struct tty_struct *tty)
{
	set_bit(TTY_LDISC, &tty->flags);
	clear_bit(TTY_LDISC_CHANGING, &tty->flags);
	wake_up(&tty_ldisc_wait);
}

@@ -496,7 +497,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
	 *	reference to the line discipline. The TTY_LDISC bit
	 *	prevents anyone taking a reference once it is clear.
	 *	We need the lock to avoid racing reference takers.
	 *
	 *	We must clear the TTY_LDISC bit here to avoid a livelock
	 *	with a userspace app continually trying to use the tty in
	 *	parallel to the change and re-referencing the tty.
	 */
	clear_bit(TTY_LDISC, &tty->flags);
	if (o_tty)
		clear_bit(TTY_LDISC, &o_tty->flags);

	spin_lock_irqsave(&tty_ldisc_lock, flags);
	if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
@@ -528,7 +536,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
	 *	If the TTY_LDISC bit is set, then we are racing against
	 *	another ldisc change
	 */
	if (!test_bit(TTY_LDISC, &tty->flags)) {
	if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
		struct tty_ldisc *ld;
		spin_unlock_irqrestore(&tty_ldisc_lock, flags);
		tty_ldisc_put(new_ldisc.ops);
@@ -536,10 +544,14 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
		tty_ldisc_deref(ld);
		goto restart;
	}

	clear_bit(TTY_LDISC, &tty->flags);
	/*
	 *	This flag is used to avoid two parallel ldisc changes. Once
	 *	open and close are fine grained locked this may work better
	 *	as a mutex shared with the open/close/hup paths
	 */
	set_bit(TTY_LDISC_CHANGING, &tty->flags);
	if (o_tty)
		clear_bit(TTY_LDISC, &o_tty->flags);
		set_bit(TTY_LDISC_CHANGING, &o_tty->flags);
	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
	
	/*
+1 −0
Original line number Diff line number Diff line
@@ -301,6 +301,7 @@ struct tty_struct {
#define TTY_PUSH 		6	/* n_tty private */
#define TTY_CLOSING 		7	/* ->close() in progress */
#define TTY_LDISC 		9	/* Line discipline attached */
#define TTY_LDISC_CHANGING 	10	/* Line discipline changing */
#define TTY_HW_COOK_OUT 	14	/* Hardware can do output cooking */
#define TTY_HW_COOK_IN 		15	/* Hardware can do input cooking */
#define TTY_PTY_LOCK 		16	/* pty private */