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

Commit cbe9352f authored by Linus Torvalds's avatar Linus Torvalds Committed by Greg Kroah-Hartman
Browse files

tty-ldisc: be more careful in 'put_ldisc' locking



Use 'atomic_dec_and_lock()' to make sure that we always hold the
tty_ldisc_lock when the ldisc count goes to zero. That way we can never
race against 'tty_ldisc_try()' increasing the count again.

Reported-by: default avatarOGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Tested-by: default avatarSergey Senozhatsky <sergey.senozhatsky@mail.by>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 65b77046
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -55,25 +55,32 @@ static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
	return ld;
}

static inline void put_ldisc(struct tty_ldisc *ld)
static void put_ldisc(struct tty_ldisc *ld)
{
	unsigned long flags;

	if (WARN_ON_ONCE(!ld))
		return;

	/*
	 * If this is the last user, free the ldisc, and
	 * release the ldisc ops.
	 *
	 * We really want an "atomic_dec_and_lock_irqsave()",
	 * but we don't have it, so this does it by hand.
	 */
	if (atomic_dec_and_test(&ld->users)) {
		unsigned long flags;
	local_irq_save(flags);
	if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
		struct tty_ldisc_ops *ldo = ld->ops;

		kfree(ld);
		spin_lock_irqsave(&tty_ldisc_lock, flags);
		ldo->refcount--;
		module_put(ldo->owner);
		spin_unlock_irqrestore(&tty_ldisc_lock, flags);

		kfree(ld);
		return;
	}
	local_irq_restore(flags);
}

/**