split dentry_kill()
... into trylocks and everything else. The latter (actual killing) is __dentry_kill(). Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
64fd72e0a4
commit
e55fd01154
1 changed files with 36 additions and 26 deletions
62
fs/dcache.c
62
fs/dcache.c
|
@ -441,36 +441,12 @@ void d_drop(struct dentry *dentry)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(d_drop);
|
EXPORT_SYMBOL(d_drop);
|
||||||
|
|
||||||
/*
|
static void __dentry_kill(struct dentry *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;
|
|
||||||
struct dentry *parent = NULL;
|
struct dentry *parent = NULL;
|
||||||
bool can_free = true;
|
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))
|
if (!IS_ROOT(dentry))
|
||||||
parent = dentry->d_parent;
|
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.
|
* The dentry is now unrecoverably dead to the world.
|
||||||
|
@ -514,10 +490,44 @@ relock:
|
||||||
can_free = false;
|
can_free = false;
|
||||||
}
|
}
|
||||||
spin_unlock(&dentry->d_lock);
|
spin_unlock(&dentry->d_lock);
|
||||||
out:
|
|
||||||
if (likely(can_free))
|
if (likely(can_free))
|
||||||
dentry_free(dentry);
|
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;
|
return parent;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
if (unlock_on_failure) {
|
||||||
|
spin_unlock(&dentry->d_lock);
|
||||||
|
cpu_relax();
|
||||||
|
}
|
||||||
|
return dentry; /* try again with same dentry */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Reference in a new issue