Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 60af22d2 authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Greg Kroah-Hartman
Browse files

tty: reorder ldisc locking



We need to release the BTM in paste_selection() when
sleeping in tty_ldisc_ref_wait to avoid deadlocks
with tty_ldisc_enable.

In tty_set_ldisc, we now always grab the BTM before
taking the ldisc_mutex in order to avoid AB-BA
deadlocks between the two.

tty_ldisc_halt potentially blocks on a workqueue
function that takes the BTM, so we must release
the BTM before calling it.

Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent be1bc288
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -319,7 +319,12 @@ int paste_selection(struct tty_struct *tty)
	poke_blanked_console();
	release_console_sem();

	ld = tty_ldisc_ref(tty);
	if (!ld) {
		tty_unlock();
		ld = tty_ldisc_ref_wait(tty);
		tty_lock();
	}

	add_wait_queue(&vc->paste_wait, &wait);
	while (sel_buffer && sel_buffer_lth > pasted) {
+20 −4
Original line number Diff line number Diff line
@@ -582,6 +582,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)

	tty_wait_until_sent(tty, 0);

	tty_lock();
	mutex_lock(&tty->ldisc_mutex);

	/*
@@ -591,13 +592,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)

	while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
		mutex_unlock(&tty->ldisc_mutex);
		tty_unlock();
		wait_event(tty_ldisc_wait,
			test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
		tty_lock();
		mutex_lock(&tty->ldisc_mutex);
	}

	tty_lock();

	set_bit(TTY_LDISC_CHANGING, &tty->flags);

	/*
@@ -634,8 +635,8 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)

	flush_scheduled_work();

	mutex_lock(&tty->ldisc_mutex);
	tty_lock();
	mutex_lock(&tty->ldisc_mutex);
	if (test_bit(TTY_HUPPED, &tty->flags)) {
		/* We were raced by the hangup method. It will have stomped
		   the ldisc data and closed the ldisc down */
@@ -782,7 +783,20 @@ void tty_ldisc_hangup(struct tty_struct *tty)
	 * Avoid racing set_ldisc or tty_ldisc_release
	 */
	mutex_lock(&tty->ldisc_mutex);
	tty_ldisc_halt(tty);

	/*
	 * this is like tty_ldisc_halt, but we need to give up
	 * the BTM before calling cancel_delayed_work_sync,
	 * which may need to wait for another function taking the BTM
	 */
	clear_bit(TTY_LDISC, &tty->flags);
	tty_unlock();
	cancel_delayed_work_sync(&tty->buf.work);
	mutex_unlock(&tty->ldisc_mutex);

	tty_lock();
	mutex_lock(&tty->ldisc_mutex);

	/* At this point we have a closed ldisc and we want to
	   reopen it. We could defer this to the next open but
	   it means auditing a lot of other paths so this is
@@ -853,8 +867,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
	 * race with the set_ldisc code path.
	 */

	tty_unlock();
	tty_ldisc_halt(tty);
	flush_scheduled_work();
	tty_lock();

	mutex_lock(&tty->ldisc_mutex);
	/*