From: Frederic Weisbecker <fweisbec@gmail.com>
To: Arnd Bergmann <arnd@arndb.de>
Cc: LKML <linux-kernel@vger.kernel.org>,
Alan Cox <alan@lxorguk.ukuu.org.uk>, Greg KH <gregkh@suse.de>,
Thomas Gleixner <tglx@linutronix.de>,
Andrew Morton <akpm@linux-foundation.org>,
John Kacur <jkacur@redhat.com>, Al Viro <viro@zeniv.linux.org.uk>,
Ingo Molnar <mingo@elte.hu>,
Arnd Bergmann <arnd@relay.de.ibm.com>
Subject: Re: [RFC 1/9] tty: replace BKL with a new tty_lock
Date: Wed, 31 Mar 2010 00:23:34 +0200 [thread overview]
Message-ID: <20100330222333.GM5078@nowhere> (raw)
In-Reply-To: <1269982580-9361-2-git-send-email-arnd@arndb.de>
On Tue, Mar 30, 2010 at 10:56:12PM +0200, Arnd Bergmann wrote:
> +/* functions for preparation of BKL removal */
> +
> +/*
> + * tty_lock_nested get the tty_lock while potentially holding it
> + *
> + * The Big TTY Mutex is a recursive lock, meaning you can take it
> + * from a thread that is already holding it.
> + * This is bad for a number of reasons, so tty_lock_nested should
> + * really be used as rarely as possible. If a code location can
> + * be shown to never get called with this held already, it should
> + * use tty_lock() instead.
> + */
> +static inline void __lockfunc tty_lock_nested(void) __acquires(kernel_lock)
> +{
> + lock_kernel();
> +}
> +static inline void tty_lock(void) __acquires(kernel_lock)
> +{
> + WARN_ON(kernel_locked());
> + lock_kernel();
> +}
> +static inline void tty_unlock(void) __releases(kernel_lock)
> +{
> + unlock_kernel();
> +}
> +#define tty_locked() (kernel_locked())
> +static inline int __reacquire_tty_lock(void)
> +{
> + return 0;
> +}
> +static inline void __release_tty_lock(void)
> +{
> +}
> +
> +#define release_tty_lock(tsk) do { } while (0)
> +#define reacquire_tty_lock(tsk) do { } while (0)
> +
> +/*
> + * mutex_lock_tty - lock a mutex without holding the BTM
> + *
> + * These three functions replace calls to mutex_lock
> + * in the tty layer, when locking on of the following
> + * mutexes:
> + * tty->ldisc_mutex
> + * tty->termios_mutex
> + * tty->atomic_write_lock
> + * port->mutex
> + * pn->all_ppp_mutex
> + *
> + * The reason we need these is to avoid an AB-BA deadlock
> + * with tty_lock(). When it can be shown that one of the
> + * above mutexes is either never acquired with the tty_lock()
> + * held, or is never held when tty_lock() is acquired, that
> + * mutex should be converted back to the regular mutex_lock
> + * function.
> + *
> + * In order to annotate the lock order, the mutex_lock_tty_on
> + * and mutex_lock_tty_off versions should be used whereever
> + * possible, to show if the mutex is used with or without
> + * tty_lock already held.
> + */
> +#define mutex_lock_tty(mutex) \
> +({ \
> + if (!mutex_trylock(mutex)) { \
> + if (tty_locked()) { \
> + __release_tty_lock(); \
> + mutex_lock(mutex); \
> + __reacquire_tty_lock(); \
> + } else \
> + mutex_lock(mutex); \
> + } \
> +})
> +
> +#define mutex_lock_tty_on(mutex) \
> +({ \
> + if (!mutex_trylock(mutex)) { \
> + if (!WARN_ON(!tty_locked())) { \
> + __release_tty_lock(); \
> + mutex_lock(mutex); \
> + __reacquire_tty_lock(); \
> + } else \
> + mutex_lock(mutex); \
> + } \
> +})
> +
> +#define mutex_lock_tty_off(mutex) \
> +({ \
> + if (!mutex_trylock(mutex)) { \
> + if (WARN_ON(tty_locked())) { \
> + __release_tty_lock(); \
> + mutex_lock(mutex); \
> + __reacquire_tty_lock(); \
> + } else \
> + mutex_lock(mutex); \
> + } \
> +})
> +
> +#define mutex_lock_interruptible_tty(mutex) \
> +({ \
> + int __ret = 0; \
> + if (!mutex_trylock(mutex)) { \
> + if (tty_locked()) { \
> + __release_tty_lock(); \
> + __ret = mutex_lock_interruptible(mutex); \
> + __reacquire_tty_lock(); \
> + } else \
> + __ret = mutex_lock_interruptible(mutex); \
> + } \
> + __ret; \
> +})
> +
> +/*
> + * wait_event*_tty -- wait for a condition with the tty lock held
> + *
> + * similar to the mutex_lock_tty family, these should be used when
> + * waiting for an event in a code location that may get called
> + * while tty_lock is held.
> + *
> + * The problem is that the condition we are waiting for might
> + * only become true if another thread runs that needs the tty_lock
> + * in order to get there.
> + *
> + * None of these should be needed and all callers should be removed
> + * when either the caller or the condition it waits for can be show
> + * to not rely on the tty_lock.
> + */
> +#define wait_event_tty(wq, condition) \
> +do { \
> + if (condition) \
> + break; \
> + release_tty_lock(current); \
> + __wait_event(wq, condition); \
> + reacquire_tty_lock(current); \
> +} while (0)
> +
> +#define wait_event_timeout_tty(wq, condition, timeout) \
> +({ \
> + long __ret = timeout; \
> + if (!(condition)) { \
> + release_tty_lock(current); \
> + __wait_event_timeout(wq, condition, __ret); \
> + reacquire_tty_lock(current); \
> + } \
> + __ret; \
> +})
> +
> +#define wait_event_interruptible_tty(wq, condition) \
> +({ \
> + int __ret = 0; \
> + if (!(condition)) { \
> + release_tty_lock(current); \
> + __wait_event_interruptible(wq, condition, __ret); \
> + reacquire_tty_lock(current); \
> + } \
> + __ret; \
> +})
> +
> +#define wait_event_interruptible_timeout_tty(wq, condition, timeout) \
> +({ \
> + long __ret = timeout; \
> + if (!(condition)) { \
> + release_tty_lock(current); \
> + __wait_event_interruptible_timeout(wq, condition, __ret); \
> + reacquire_tty_lock(current); \
> + } \
> + __ret; \
> +})
Ouch, these helpers make me living again all the insane things I had to
do in reiserfs :-)
I first had doubts about this Big Tty Mutex (or whatever german meaning :-)
Because I thought this only carries the problem forward, or even
worst: now that it's not the bkl anymore, fewer people will even care about
removing this new big lock.
But now I actually think this is a good thing as every single tricky points
is underlined explicitly with these wait_event_tty, mutex_lock_tty, and so...
It's not anymore something released under us on schedule, it's not something
that might or might not be acquired recursively.
Removing this big lock later will then be easier as we can do it with more
granularity and visibility.
This is at least the experience I had with reiserfs. Its code _looks_
crappier than ever since 2.6.33, but it's a wrong appearance.
Now it shows which points require the reiserfs lock to be released because
there is an event dependency and it shows what are these dependencies.
The fact we can use lockdep in such a scheme plays a huge role btw.
Things are much clearer now, and I have even released some small areas
from the reiserfs lock because the explicit locking made it clear enough
to prove it fine.
If reiserfs wasn't obsolete, I would have probably pushed the effort further
to turn it into a granular locking, because the current state makes it
possible.
Now here we are talking about tty, and tty is not obsolete at all, so
I expect this is going to reach the current reiserfs level, plus a
subsequent and progressive state of locking granularity work, until
a complete exorcism.
FWIW, I'm all for this patchset.
next prev parent reply other threads:[~2010-03-30 22:23 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-03-30 20:56 [RFC 0/9] BKL conversion in TTY drivers Arnd Bergmann
2010-03-30 20:56 ` [RFC 1/9] tty: replace BKL with a new tty_lock Arnd Bergmann
2010-03-30 22:23 ` Frederic Weisbecker [this message]
2010-03-30 20:56 ` [RFC 2/9] tty: make atomic_write_lock release tty_lock Arnd Bergmann
2010-03-30 20:56 ` [RFC 3/9] tty: make tty_port->mutex nest under tty_lock Arnd Bergmann
2010-03-30 20:56 ` [RFC 4/9] tty: make termios mutex " Arnd Bergmann
2010-03-30 20:56 ` [RFC 5/9] tty: make ldisc_mutex " Arnd Bergmann
2010-03-30 20:56 ` [RFC 6/9] tty: never hold tty_lock() while getting tty_mutex Arnd Bergmann
2010-03-30 20:56 ` [RFC 7/9] ppp: use big tty mutex Arnd Bergmann
2010-03-31 4:37 ` Américo Wang
2010-03-31 7:39 ` Arnd Bergmann
2010-03-30 20:56 ` [RFC 8/9] tty: release tty lock when blocking Arnd Bergmann
2010-03-30 20:56 ` [RFC 9/9] tty: implement BTM as mutex instead of BKL Arnd Bergmann
2010-03-30 22:50 ` Frederic Weisbecker
2010-03-30 22:37 ` [RFC 0/9] BKL conversion in TTY drivers Alan Cox
2010-03-31 7:57 ` Arnd Bergmann
2010-03-31 10:02 ` Alan Cox
2010-04-01 12:51 ` Arnd Bergmann
2010-04-01 14:17 ` Alan Cox
2010-04-01 15:24 ` Greg KH
2010-04-01 19:10 ` Arnd Bergmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20100330222333.GM5078@nowhere \
--to=fweisbec@gmail.com \
--cc=akpm@linux-foundation.org \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=arnd@arndb.de \
--cc=arnd@relay.de.ibm.com \
--cc=gregkh@suse.de \
--cc=jkacur@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=tglx@linutronix.de \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox