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);
|
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)
|
static void shrink_dentry_list(struct list_head *list)
|
||||||
{
|
{
|
||||||
struct dentry *dentry;
|
struct dentry *dentry, *parent;
|
||||||
|
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -863,22 +825,35 @@ static void shrink_dentry_list(struct list_head *list)
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
parent = dentry_kill(dentry, 0);
|
||||||
/*
|
/*
|
||||||
* If 'try_to_prune()' returns a dentry, it will
|
* If dentry_kill returns NULL, we have nothing more to do.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
dentry = try_prune_one_dentry(dentry);
|
if (!parent) {
|
||||||
|
rcu_read_lock();
|
||||||
rcu_read_lock();
|
continue;
|
||||||
if (dentry) {
|
}
|
||||||
|
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);
|
d_shrink_add(dentry, list);
|
||||||
spin_unlock(&dentry->d_lock);
|
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();
|
rcu_read_unlock();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue