Loading drivers/char/tty_ldisc.c +21 −9 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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); } Loading Loading @@ -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)) { Loading Loading @@ -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); Loading @@ -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); /* Loading include/linux/tty.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading
drivers/char/tty_ldisc.c +21 −9 Original line number Diff line number Diff line Loading @@ -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; } Loading Loading @@ -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); } Loading Loading @@ -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)) { Loading Loading @@ -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); Loading @@ -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); /* Loading
include/linux/tty.h +1 −0 Original line number Diff line number Diff line Loading @@ -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 */ Loading