[Devel] [PATCH RHEL7 COMMIT] ms/dcache: dealing with the rest of shrink_dentry_list() livelock

Konstantin Khorenko khorenko at virtuozzo.com
Fri May 27 01:53:13 PDT 2016


The commit is pushed to "branch-rh7-3.10.0-327.18.2.vz7.14.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.18.2.vz7.14.8
------>
commit 92c0e0c9d27550fceb656796d479f83c942608f1
Author: Al Viro <viro at zeniv.linux.org.uk>
Date:   Fri May 27 12:53:13 2016 +0400

    ms/dcache: dealing with the rest of shrink_dentry_list() livelock
    
    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 at zeniv.linux.org.uk>
    (cherry picked from commit b2b80195d8829921506880f6dccd21cabd163d0d)
    Signed-off-by: Vladimir Davydov <vdavydov at virtuozzo.com>
---
 fs/dcache.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/fs/dcache.c b/fs/dcache.c
index a287c5a..7b75b48 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -913,8 +913,26 @@ static void shrink_dentry_list(struct list_head *list)
 		 * 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;
+		}
 	}
 }
 


More information about the Devel mailing list