[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20160301234500.791010389@linuxfoundation.org>
Date: Tue, 01 Mar 2016 23:50:59 +0000
From: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
To: <linux-kernel@...r.kernel.org>
Cc: Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
<stable@...r.kernel.org>, Al Viro <viro@...iv.linux.org.uk>
Subject: [PATCH 3.14 029/130] dealing with the rest of shrink_dentry_list() livelock
3.14-stable review patch. If anyone has any objections, please let me know.
------------------
From: Al Viro <viro@...iv.linux.org.uk>
commit b2b80195d8829921506880f6dccd21cabd163d0d upstream.
We have the same problem with ->d_lock order in the inner loop, where
we are dropping references to ancestors. Same solution, basically -
instead of using dentry_kill() we use lock_parent() (introduced in the
previous commit) to get that lock in a safe way, recheck ->d_count
(in case if lock_parent() has ended up dropping and retaking ->d_lock
and somebody managed to grab a reference during that window), trylock
the inode->i_lock and use __dentry_kill() to do the rest.
Signed-off-by: Al Viro <viro@...iv.linux.org.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@...uxfoundation.org>
---
fs/dcache.c | 22 ++++++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -886,8 +886,26 @@ static void shrink_dentry_list(struct li
* fragmentation.
*/
dentry = parent;
- while (dentry && !lockref_put_or_lock(&dentry->d_lockref))
- dentry = dentry_kill(dentry, 1);
+ while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) {
+ parent = lock_parent(dentry);
+ if (dentry->d_lockref.count != 1) {
+ dentry->d_lockref.count--;
+ spin_unlock(&dentry->d_lock);
+ if (parent)
+ spin_unlock(&parent->d_lock);
+ break;
+ }
+ inode = dentry->d_inode; /* can't be NULL */
+ if (unlikely(!spin_trylock(&inode->i_lock))) {
+ spin_unlock(&dentry->d_lock);
+ if (parent)
+ spin_unlock(&parent->d_lock);
+ cpu_relax();
+ continue;
+ }
+ __dentry_kill(dentry);
+ dentry = parent;
+ }
}
}
Powered by blists - more mailing lists