Al Viro 046b961b45 shrink_dentry_list(): take parent's ->d_lock earlier
The cause of livelocks there is that we are taking ->d_lock on
dentry and its parent in the wrong order, forcing us to use
trylock on the parent's one.  d_walk() takes them in the right
order, and unfortunately it's not hard to create a situation
when shrink_dentry_list() can't make progress since trylock
keeps failing, and shrink_dcache_parent() or check_submounts_and_drop()
keeps calling d_walk() disrupting the very shrink_dentry_list() it's
waiting for.

Solution is straightforward - if that trylock fails, let's unlock
the dentry itself and take locks in the right order.  We need to
stabilize ->d_parent without holding ->d_lock, but that's doable
using RCU.  And we'd better do that in the very beginning of the
loop in shrink_dentry_list(), since the checks on refcount, etc.
would need to be redone anyway.

That deals with a half of the problem - killing dentries on the
shrink list itself.  Another one (dropping their parents) is
in the next commit.

locking parent is interesting - it would be easy to do rcu_read_lock(),
lock whatever we think is a parent, lock dentry itself and check
if the parent is still the right one.  Except that we need to check
that *before* locking the dentry, or we are risking taking ->d_lock
out of order.  Fortunately, once the D1 is locked, we can check if
D2->d_parent is equal to D1 without the need to lock D2; D2->d_parent
can start or stop pointing to D1 only under D1->d_lock, so taking
D1->d_lock is enough.  In other words, the right solution is
rcu_read_lock/lock what looks like parent right now/check if it's
still our parent/rcu_read_unlock/lock the child.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2014-05-30 11:03:21 -04:00
..
2014-05-06 13:04:59 -07:00
2014-04-28 16:43:44 +02:00
2013-12-04 12:27:46 +01:00
2014-04-07 10:17:30 -07:00
2014-01-25 03:14:05 -05:00
2014-05-05 09:31:33 +03:00
2013-12-05 16:36:21 -06:00
2013-06-29 12:57:04 +04:00
2013-10-24 23:34:54 -04:00
2014-04-19 13:23:31 -07:00
2014-04-04 15:50:08 -07:00
2013-11-09 00:16:20 -05:00
2013-10-24 23:34:54 -04:00
2014-02-07 16:08:57 -08:00
2014-02-07 16:08:57 -08:00
2014-04-01 23:19:09 -04:00
2013-11-23 22:33:47 -08:00
2014-04-01 23:19:08 -04:00
2014-04-01 23:19:08 -04:00
2014-04-01 23:19:09 -04:00
2013-10-24 23:34:54 -04:00
2014-05-28 01:54:52 -04:00
2013-11-09 00:16:31 -05:00
2014-04-16 11:53:08 -07:00