mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-05 02:19:51 +00:00
fold try_prune_one_dentry()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
03b3b889e7
commit
5c47e6d0ad
1 changed files with 25 additions and 50 deletions
75
fs/dcache.c
75
fs/dcache.c
|
@ -787,47 +787,9 @@ void d_prune_aliases(struct inode *inode)
|
|||
}
|
||||
EXPORT_SYMBOL(d_prune_aliases);
|
||||
|
||||
/*
|
||||
* Try to throw away a dentry - free the inode, dput the parent.
|
||||
* Requires dentry->d_lock is held, and dentry->d_count == 0.
|
||||
* Releases dentry->d_lock.
|
||||
*
|
||||
* This may fail if locks cannot be acquired no problem, just try again.
|
||||
*/
|
||||
static struct dentry * try_prune_one_dentry(struct dentry *dentry)
|
||||
__releases(dentry->d_lock)
|
||||
{
|
||||
struct dentry *parent;
|
||||
|
||||
parent = dentry_kill(dentry, 0);
|
||||
/*
|
||||
* If dentry_kill returns NULL, we have nothing more to do.
|
||||
* if it returns the same dentry, trylocks failed. In either
|
||||
* case, just loop again.
|
||||
*
|
||||
* Otherwise, we need to prune ancestors too. This is necessary
|
||||
* to prevent quadratic behavior of shrink_dcache_parent(), but
|
||||
* is also expected to be beneficial in reducing dentry cache
|
||||
* fragmentation.
|
||||
*/
|
||||
if (!parent)
|
||||
return NULL;
|
||||
if (parent == dentry)
|
||||
return dentry;
|
||||
|
||||
/* Prune ancestors. */
|
||||
dentry = parent;
|
||||
while (dentry) {
|
||||
if (lockref_put_or_lock(&dentry->d_lockref))
|
||||
return NULL;
|
||||
dentry = dentry_kill(dentry, 1);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void shrink_dentry_list(struct list_head *list)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct dentry *dentry, *parent;
|
||||
|
||||
rcu_read_lock();
|
||||
for (;;) {
|
||||
|
@ -863,22 +825,35 @@ static void shrink_dentry_list(struct list_head *list)
|
|||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
parent = dentry_kill(dentry, 0);
|
||||
/*
|
||||
* If 'try_to_prune()' returns a dentry, it will
|
||||
* be the same one we passed in, and d_lock will
|
||||
* have been held the whole time, so it will not
|
||||
* have been added to any other lists. We failed
|
||||
* to get the inode lock.
|
||||
*
|
||||
* We just add it back to the shrink list.
|
||||
* If dentry_kill returns NULL, we have nothing more to do.
|
||||
*/
|
||||
dentry = try_prune_one_dentry(dentry);
|
||||
|
||||
rcu_read_lock();
|
||||
if (dentry) {
|
||||
if (!parent) {
|
||||
rcu_read_lock();
|
||||
continue;
|
||||
}
|
||||
if (unlikely(parent == dentry)) {
|
||||
/*
|
||||
* trylocks have failed and d_lock has been held the
|
||||
* whole time, so it could not have been added to any
|
||||
* other lists. Just add it back to the shrink list.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
d_shrink_add(dentry, list);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* We need to prune ancestors too. This is necessary to prevent
|
||||
* quadratic behavior of shrink_dcache_parent(), but is also
|
||||
* expected to be beneficial in reducing dentry cache
|
||||
* fragmentation.
|
||||
*/
|
||||
dentry = parent;
|
||||
while (dentry && !lockref_put_or_lock(&dentry->d_lockref))
|
||||
dentry = dentry_kill(dentry, 1);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue