tty: Add lock/unlock ldisc pair functions
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>
This commit is contained in:
Родитель
137084bbad
Коммит
d2c438905f
|
@ -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
|
||||
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче