Skip to content

Commit

Permalink
tty: Add lock/unlock ldisc pair functions
Browse files Browse the repository at this point in the history
Just as the tty pair must be locked in a stable sequence
(ie, independent of which is consider the 'other' tty), so must
the ldisc pair be locked in a stable sequence as well.

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
peterhurley authored and gregkh committed Jul 23, 2013
1 parent 137084b commit d2c4389
Showing 1 changed file with 87 additions and 0 deletions.
87 changes: 87 additions & 0 deletions drivers/tty/tty_ldisc.c
Expand Up @@ -31,6 +31,13 @@
#define tty_ldisc_debug(tty, f, args...)
#endif

/* lockdep nested classes for tty->ldisc_sem */
enum {
LDISC_SEM_NORMAL,
LDISC_SEM_OTHER,
};


/*
* This guards the refcounted line discipline lists. The lock
* must be taken with irqs off because there are hangup path
Expand Down Expand Up @@ -351,6 +358,86 @@ void tty_ldisc_deref(struct tty_ldisc *ld)
}
EXPORT_SYMBOL_GPL(tty_ldisc_deref);


static inline int __lockfunc
tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout)
{
return ldsem_down_write(&tty->ldisc_sem, timeout);
}

static inline int __lockfunc
tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout)
{
return ldsem_down_write_nested(&tty->ldisc_sem,
LDISC_SEM_OTHER, timeout);
}

static inline void tty_ldisc_unlock(struct tty_struct *tty)
{
return ldsem_up_write(&tty->ldisc_sem);
}

static int __lockfunc
tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2,
unsigned long timeout)
{
int ret;

if (tty < tty2) {
ret = tty_ldisc_lock(tty, timeout);
if (ret) {
ret = tty_ldisc_lock_nested(tty2, timeout);
if (!ret)
tty_ldisc_unlock(tty);
}
} else {
/* if this is possible, it has lots of implications */
WARN_ON_ONCE(tty == tty2);
if (tty2 && tty != tty2) {
ret = tty_ldisc_lock(tty2, timeout);
if (ret) {
ret = tty_ldisc_lock_nested(tty, timeout);
if (!ret)
tty_ldisc_unlock(tty2);
}
} else
ret = tty_ldisc_lock(tty, timeout);
}

if (!ret)
return -EBUSY;

set_bit(TTY_LDISC_HALTED, &tty->flags);
if (tty2)
set_bit(TTY_LDISC_HALTED, &tty2->flags);
return 0;
}

static void __lockfunc
tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2)
{
tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT);
}

static void __lockfunc tty_ldisc_unlock_pair(struct tty_struct *tty,
struct tty_struct *tty2)
{
tty_ldisc_unlock(tty);
if (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_enable - allow ldisc use
* @tty: terminal to activate ldisc on
Expand Down

0 comments on commit d2c4389

Please sign in to comment.