mirror of
https://github.com/armbian/linux.git
synced 2026-01-06 10:13:00 -08:00
tty: Replace ldisc locking with ldisc_sem
Line discipline locking was performed with a combination of
a mutex, a status bit, a count, and a waitqueue -- basically,
a rw semaphore.
Replace the existing combination with an ld_semaphore.
Fixes:
1) the 'reference acquire after ldisc locked' bug
2) the over-complicated halt mechanism
3) lock order wrt. tty_lock()
4) dropping locks while changing ldisc
5) previously unidentified deadlock while locking ldisc from
both linked ttys concurrently
6) previously unidentified recursive deadlocks
Adds much-needed lockdep diagnostics.
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
d2c438905f
commit
36697529b5
@@ -429,7 +429,7 @@ static void flush_to_ldisc(struct work_struct *work)
|
||||
return;
|
||||
|
||||
disc = tty_ldisc_ref(tty);
|
||||
if (disc == NULL) /* !TTY_LDISC */
|
||||
if (disc == NULL)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&buf->lock, flags);
|
||||
|
||||
@@ -1388,8 +1388,7 @@ static int tty_reopen(struct tty_struct *tty)
|
||||
struct tty_driver *driver = tty->driver;
|
||||
|
||||
if (test_bit(TTY_CLOSING, &tty->flags) ||
|
||||
test_bit(TTY_HUPPING, &tty->flags) ||
|
||||
test_bit(TTY_LDISC_CHANGING, &tty->flags))
|
||||
test_bit(TTY_HUPPING, &tty->flags))
|
||||
return -EIO;
|
||||
|
||||
if (driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
@@ -1405,7 +1404,7 @@ static int tty_reopen(struct tty_struct *tty)
|
||||
}
|
||||
tty->count++;
|
||||
|
||||
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
|
||||
WARN_ON(!tty->ldisc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3017,7 +3016,7 @@ void initialize_tty_struct(struct tty_struct *tty,
|
||||
tty->pgrp = NULL;
|
||||
mutex_init(&tty->legacy_mutex);
|
||||
mutex_init(&tty->termios_mutex);
|
||||
mutex_init(&tty->ldisc_mutex);
|
||||
init_ldsem(&tty->ldisc_sem);
|
||||
init_waitqueue_head(&tty->write_wait);
|
||||
init_waitqueue_head(&tty->read_wait);
|
||||
INIT_WORK(&tty->hangup_work, do_tty_hangup);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -238,7 +238,7 @@ struct tty_struct {
|
||||
int index;
|
||||
|
||||
/* Protects ldisc changes: Lock tty not pty */
|
||||
struct mutex ldisc_mutex;
|
||||
struct ld_semaphore ldisc_sem;
|
||||
struct tty_ldisc *ldisc;
|
||||
|
||||
struct mutex atomic_write_lock;
|
||||
@@ -305,8 +305,6 @@ struct tty_file_private {
|
||||
#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */
|
||||
#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_LDISC_OPEN 11 /* Line discipline is open */
|
||||
#define TTY_PTY_LOCK 16 /* pty private */
|
||||
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
|
||||
|
||||
@@ -203,8 +203,7 @@ struct tty_ldisc_ops {
|
||||
|
||||
struct tty_ldisc {
|
||||
struct tty_ldisc_ops *ops;
|
||||
atomic_t users;
|
||||
wait_queue_head_t wq_idle;
|
||||
struct tty_struct *tty;
|
||||
};
|
||||
|
||||
#define TTY_LDISC_MAGIC 0x5403
|
||||
|
||||
Reference in New Issue
Block a user