Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 54536
b: refs/heads/master
c: d52b908
h: refs/heads/master
v: v3
  • Loading branch information
Miklos Szeredi authored and Linus Torvalds committed May 8, 2007
1 parent d4b9bd8 commit cd35346
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 38 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 97dc32cdb1b53832801159d5f634b41aad9d0a23
refs/heads/master: d52b908646b88cb1952ab8c9b2d4423908a23f11
104 changes: 67 additions & 37 deletions trunk/fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,28 @@ static void dentry_iput(struct dentry * dentry)
}
}

/**
* d_kill - kill dentry and return parent
* @dentry: dentry to kill
*
* Called with dcache_lock and d_lock, releases both. The dentry must
* already be unhashed and removed from the LRU.
*
* If this is the root of the dentry tree, return NULL.
*/
static struct dentry *d_kill(struct dentry *dentry)
{
struct dentry *parent;

list_del(&dentry->d_u.d_child);
dentry_stat.nr_dentry--; /* For d_free, below */
/*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry);
parent = dentry->d_parent;
d_free(dentry);
return dentry == parent ? NULL : parent;
}

/*
* This is dput
*
Expand Down Expand Up @@ -189,28 +211,17 @@ void dput(struct dentry *dentry)

unhash_it:
__d_drop(dentry);

kill_it: {
struct dentry *parent;

/* If dentry was on d_lru list
* delete it from there
*/
if (!list_empty(&dentry->d_lru)) {
list_del(&dentry->d_lru);
dentry_stat.nr_unused--;
}
list_del(&dentry->d_u.d_child);
dentry_stat.nr_dentry--; /* For d_free, below */
/*drops the locks, at that point nobody can reach this dentry */
dentry_iput(dentry);
parent = dentry->d_parent;
d_free(dentry);
if (dentry == parent)
return;
dentry = parent;
goto repeat;
kill_it:
/* If dentry was on d_lru list
* delete it from there
*/
if (!list_empty(&dentry->d_lru)) {
list_del(&dentry->d_lru);
dentry_stat.nr_unused--;
}
dentry = d_kill(dentry);
if (dentry)
goto repeat;
}

/**
Expand Down Expand Up @@ -371,29 +382,48 @@ void d_prune_aliases(struct inode *inode)
* Throw away a dentry - free the inode, dput the parent. This requires that
* the LRU list has already been removed.
*
* If prune_parents is true, try to prune ancestors as well.
*
* Called with dcache_lock, drops it and then regains.
* Called with dentry->d_lock held, drops it.
*/
static void prune_one_dentry(struct dentry * dentry)
static void prune_one_dentry(struct dentry * dentry, int prune_parents)
{
struct dentry * parent;

__d_drop(dentry);
list_del(&dentry->d_u.d_child);
dentry_stat.nr_dentry--; /* For d_free, below */
dentry_iput(dentry);
parent = dentry->d_parent;
d_free(dentry);
if (parent != dentry)
dput(parent);
dentry = d_kill(dentry);
if (!prune_parents) {
dput(dentry);
spin_lock(&dcache_lock);
return;
}

/*
* Prune ancestors. Locking is simpler than in dput(),
* because dcache_lock needs to be taken anyway.
*/
spin_lock(&dcache_lock);
while (dentry) {
if (!atomic_dec_and_lock(&dentry->d_count, &dentry->d_lock))
return;

if (dentry->d_op && dentry->d_op->d_delete)
dentry->d_op->d_delete(dentry);
if (!list_empty(&dentry->d_lru)) {
list_del(&dentry->d_lru);
dentry_stat.nr_unused--;
}
__d_drop(dentry);
dentry = d_kill(dentry);
spin_lock(&dcache_lock);
}
}

/**
* prune_dcache - shrink the dcache
* @count: number of entries to try and free
* @sb: if given, ignore dentries for other superblocks
* which are being unmounted.
* @prune_parents: if true, try to prune ancestors as well in one go
*
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
Expand All @@ -404,7 +434,7 @@ static void prune_one_dentry(struct dentry * dentry)
* all the dentries are in use.
*/

static void prune_dcache(int count, struct super_block *sb)
static void prune_dcache(int count, struct super_block *sb, int prune_parents)
{
spin_lock(&dcache_lock);
for (; count ; count--) {
Expand Down Expand Up @@ -464,7 +494,7 @@ static void prune_dcache(int count, struct super_block *sb)
* without taking the s_umount lock (I already hold it).
*/
if (sb && dentry->d_sb == sb) {
prune_one_dentry(dentry);
prune_one_dentry(dentry, prune_parents);
continue;
}
/*
Expand All @@ -479,7 +509,7 @@ static void prune_dcache(int count, struct super_block *sb)
s_umount = &dentry->d_sb->s_umount;
if (down_read_trylock(s_umount)) {
if (dentry->d_sb->s_root != NULL) {
prune_one_dentry(dentry);
prune_one_dentry(dentry, prune_parents);
up_read(s_umount);
continue;
}
Expand Down Expand Up @@ -550,7 +580,7 @@ void shrink_dcache_sb(struct super_block * sb)
spin_unlock(&dentry->d_lock);
continue;
}
prune_one_dentry(dentry);
prune_one_dentry(dentry, 1);
cond_resched_lock(&dcache_lock);
goto repeat;
}
Expand Down Expand Up @@ -829,7 +859,7 @@ void shrink_dcache_parent(struct dentry * parent)
int found;

while ((found = select_parent(parent)) != 0)
prune_dcache(found, parent->d_sb);
prune_dcache(found, parent->d_sb, 1);
}

/*
Expand All @@ -849,7 +879,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
if (nr) {
if (!(gfp_mask & __GFP_FS))
return -1;
prune_dcache(nr, NULL);
prune_dcache(nr, NULL, 0);
}
return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
}
Expand Down

0 comments on commit cd35346

Please sign in to comment.