diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-05-29 09:11:45 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-05-30 11:10:33 -0400 |
commit | b2b80195d8829921506880f6dccd21cabd163d0d (patch) | |
tree | 4c0845c5bdbcfba145459fb1a5f9853f762fb64c /fs | |
parent | 046b961b45f93a92e4c70525a12f3d378bced130 (diff) |
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@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/dcache.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/fs/dcache.c b/fs/dcache.c index d54a99baf4f3..eb7c7255470c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -885,8 +885,26 @@ static void shrink_dentry_list(struct list_head *list) | |||
885 | * fragmentation. | 885 | * fragmentation. |
886 | */ | 886 | */ |
887 | dentry = parent; | 887 | dentry = parent; |
888 | while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) | 888 | while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) { |
889 | dentry = dentry_kill(dentry, 1); | 889 | parent = lock_parent(dentry); |
890 | if (dentry->d_lockref.count != 1) { | ||
891 | dentry->d_lockref.count--; | ||
892 | spin_unlock(&dentry->d_lock); | ||
893 | if (parent) | ||
894 | spin_unlock(&parent->d_lock); | ||
895 | break; | ||
896 | } | ||
897 | inode = dentry->d_inode; /* can't be NULL */ | ||
898 | if (unlikely(!spin_trylock(&inode->i_lock))) { | ||
899 | spin_unlock(&dentry->d_lock); | ||
900 | if (parent) | ||
901 | spin_unlock(&parent->d_lock); | ||
902 | cpu_relax(); | ||
903 | continue; | ||
904 | } | ||
905 | __dentry_kill(dentry); | ||
906 | dentry = parent; | ||
907 | } | ||
890 | } | 908 | } |
891 | } | 909 | } |
892 | 910 | ||