Commit 36697529 authored by Peter Hurley's avatar Peter Hurley Committed by Greg Kroah-Hartman

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: default avatarPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d2c43890
...@@ -429,7 +429,7 @@ static void flush_to_ldisc(struct work_struct *work) ...@@ -429,7 +429,7 @@ static void flush_to_ldisc(struct work_struct *work)
return; return;
disc = tty_ldisc_ref(tty); disc = tty_ldisc_ref(tty);
if (disc == NULL) /* !TTY_LDISC */ if (disc == NULL)
return; return;
spin_lock_irqsave(&buf->lock, flags); spin_lock_irqsave(&buf->lock, flags);
......
...@@ -1388,8 +1388,7 @@ static int tty_reopen(struct tty_struct *tty) ...@@ -1388,8 +1388,7 @@ static int tty_reopen(struct tty_struct *tty)
struct tty_driver *driver = tty->driver; struct tty_driver *driver = tty->driver;
if (test_bit(TTY_CLOSING, &tty->flags) || if (test_bit(TTY_CLOSING, &tty->flags) ||
test_bit(TTY_HUPPING, &tty->flags) || test_bit(TTY_HUPPING, &tty->flags))
test_bit(TTY_LDISC_CHANGING, &tty->flags))
return -EIO; return -EIO;
if (driver->type == TTY_DRIVER_TYPE_PTY && if (driver->type == TTY_DRIVER_TYPE_PTY &&
...@@ -1405,7 +1404,7 @@ static int tty_reopen(struct tty_struct *tty) ...@@ -1405,7 +1404,7 @@ static int tty_reopen(struct tty_struct *tty)
} }
tty->count++; tty->count++;
WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); WARN_ON(!tty->ldisc);
return 0; return 0;
} }
...@@ -3017,7 +3016,7 @@ void initialize_tty_struct(struct tty_struct *tty, ...@@ -3017,7 +3016,7 @@ void initialize_tty_struct(struct tty_struct *tty,
tty->pgrp = NULL; tty->pgrp = NULL;
mutex_init(&tty->legacy_mutex); mutex_init(&tty->legacy_mutex);
mutex_init(&tty->termios_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->write_wait);
init_waitqueue_head(&tty->read_wait); init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup); INIT_WORK(&tty->hangup_work, do_tty_hangup);
......
This diff is collapsed.
...@@ -238,7 +238,7 @@ struct tty_struct { ...@@ -238,7 +238,7 @@ struct tty_struct {
int index; int index;
/* Protects ldisc changes: Lock tty not pty */ /* Protects ldisc changes: Lock tty not pty */
struct mutex ldisc_mutex; struct ld_semaphore ldisc_sem;
struct tty_ldisc *ldisc; struct tty_ldisc *ldisc;
struct mutex atomic_write_lock; struct mutex atomic_write_lock;
...@@ -305,8 +305,6 @@ struct tty_file_private { ...@@ -305,8 +305,6 @@ struct tty_file_private {
#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ #define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */
#define TTY_PUSH 6 /* n_tty private */ #define TTY_PUSH 6 /* n_tty private */
#define TTY_CLOSING 7 /* ->close() in progress */ #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_LDISC_OPEN 11 /* Line discipline is open */
#define TTY_PTY_LOCK 16 /* pty private */ #define TTY_PTY_LOCK 16 /* pty private */
#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ #define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */
......
...@@ -203,8 +203,7 @@ struct tty_ldisc_ops { ...@@ -203,8 +203,7 @@ struct tty_ldisc_ops {
struct tty_ldisc { struct tty_ldisc {
struct tty_ldisc_ops *ops; struct tty_ldisc_ops *ops;
atomic_t users; struct tty_struct *tty;
wait_queue_head_t wq_idle;
}; };
#define TTY_LDISC_MAGIC 0x5403 #define TTY_LDISC_MAGIC 0x5403
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment