| From e55fd011549eae01a230e3cace6f4d031b6a3453 Mon Sep 17 00:00:00 2001 |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| Date: Wed, 28 May 2014 13:51:12 -0400 |
| Subject: split dentry_kill() |
| |
| From: Al Viro <viro@zeniv.linux.org.uk> |
| |
| commit e55fd011549eae01a230e3cace6f4d031b6a3453 upstream. |
| |
| ... into trylocks and everything else. The latter (actual killing) |
| is __dentry_kill(). |
| |
| Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/dcache.c | 62 ++++++++++++++++++++++++++++++++++-------------------------- |
| 1 file changed, 36 insertions(+), 26 deletions(-) |
| |
| --- a/fs/dcache.c |
| +++ b/fs/dcache.c |
| @@ -439,36 +439,12 @@ void d_drop(struct dentry *dentry) |
| } |
| EXPORT_SYMBOL(d_drop); |
| |
| -/* |
| - * Finish off a dentry we've decided to kill. |
| - * dentry->d_lock must be held, returns with it unlocked. |
| - * If ref is non-zero, then decrement the refcount too. |
| - * Returns dentry requiring refcount drop, or NULL if we're done. |
| - */ |
| -static struct dentry * |
| -dentry_kill(struct dentry *dentry, int unlock_on_failure) |
| - __releases(dentry->d_lock) |
| +static void __dentry_kill(struct dentry *dentry) |
| { |
| - struct inode *inode; |
| struct dentry *parent = NULL; |
| bool can_free = true; |
| - |
| - inode = dentry->d_inode; |
| - if (inode && !spin_trylock(&inode->i_lock)) { |
| -relock: |
| - if (unlock_on_failure) { |
| - spin_unlock(&dentry->d_lock); |
| - cpu_relax(); |
| - } |
| - return dentry; /* try again with same dentry */ |
| - } |
| if (!IS_ROOT(dentry)) |
| parent = dentry->d_parent; |
| - if (parent && !spin_trylock(&parent->d_lock)) { |
| - if (inode) |
| - spin_unlock(&inode->i_lock); |
| - goto relock; |
| - } |
| |
| /* |
| * The dentry is now unrecoverably dead to the world. |
| @@ -512,10 +488,44 @@ relock: |
| can_free = false; |
| } |
| spin_unlock(&dentry->d_lock); |
| -out: |
| if (likely(can_free)) |
| dentry_free(dentry); |
| +} |
| + |
| +/* |
| + * Finish off a dentry we've decided to kill. |
| + * dentry->d_lock must be held, returns with it unlocked. |
| + * If ref is non-zero, then decrement the refcount too. |
| + * Returns dentry requiring refcount drop, or NULL if we're done. |
| + */ |
| +static struct dentry * |
| +dentry_kill(struct dentry *dentry, int unlock_on_failure) |
| + __releases(dentry->d_lock) |
| +{ |
| + struct inode *inode = dentry->d_inode; |
| + struct dentry *parent = NULL; |
| + |
| + if (inode && unlikely(!spin_trylock(&inode->i_lock))) |
| + goto failed; |
| + |
| + if (!IS_ROOT(dentry)) { |
| + parent = dentry->d_parent; |
| + if (unlikely(!spin_trylock(&parent->d_lock))) { |
| + if (inode) |
| + spin_unlock(&inode->i_lock); |
| + goto failed; |
| + } |
| + } |
| + |
| + __dentry_kill(dentry); |
| return parent; |
| + |
| +failed: |
| + if (unlock_on_failure) { |
| + spin_unlock(&dentry->d_lock); |
| + cpu_relax(); |
| + } |
| + return dentry; /* try again with same dentry */ |
| } |
| |
| /* |