Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 28569
b: refs/heads/master
c: 0feae5c
h: refs/heads/master
i:
  28567: ef85065
v: v3
  • Loading branch information
NeilBrown authored and Linus Torvalds committed Jun 22, 2006
1 parent 1153537 commit ab98958
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 9 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: de047c1bcd7f7bcfbdc29eb5b439fb332594da3f
refs/heads/master: 0feae5c47aabdde59cbbec32d150e17102de37f0
66 changes: 60 additions & 6 deletions trunk/fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,8 @@ static inline void prune_one_dentry(struct dentry * dentry)
/**
* 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.
*
* Shrink the dcache. This is done when we need
* more memory, or simply when we need to unmount
Expand All @@ -392,16 +394,29 @@ static inline void prune_one_dentry(struct dentry * dentry)
* all the dentries are in use.
*/

static void prune_dcache(int count)
static void prune_dcache(int count, struct super_block *sb)
{
spin_lock(&dcache_lock);
for (; count ; count--) {
struct dentry *dentry;
struct list_head *tmp;
struct rw_semaphore *s_umount;

cond_resched_lock(&dcache_lock);

tmp = dentry_unused.prev;
if (unlikely(sb)) {
/* Try to find a dentry for this sb, but don't try
* too hard, if they aren't near the tail they will
* be moved down again soon
*/
int skip = count;
while (skip && tmp != &dentry_unused &&
list_entry(tmp, struct dentry, d_lru)->d_sb != sb) {
skip--;
tmp = tmp->prev;
}
}
if (tmp == &dentry_unused)
break;
list_del_init(tmp);
Expand All @@ -427,7 +442,45 @@ static void prune_dcache(int count)
spin_unlock(&dentry->d_lock);
continue;
}
prune_one_dentry(dentry);
/*
* If the dentry is not DCACHED_REFERENCED, it is time
* to remove it from the dcache, provided the super block is
* NULL (which means we are trying to reclaim memory)
* or this dentry belongs to the same super block that
* we want to shrink.
*/
/*
* If this dentry is for "my" filesystem, then I can prune it
* without taking the s_umount lock (I already hold it).
*/
if (sb && dentry->d_sb == sb) {
prune_one_dentry(dentry);
continue;
}
/*
* ...otherwise we need to be sure this filesystem isn't being
* unmounted, otherwise we could race with
* generic_shutdown_super(), and end up holding a reference to
* an inode while the filesystem is unmounted.
* So we try to get s_umount, and make sure s_root isn't NULL.
* (Take a local copy of s_umount to avoid a use-after-free of
* `dentry').
*/
s_umount = &dentry->d_sb->s_umount;
if (down_read_trylock(s_umount)) {
if (dentry->d_sb->s_root != NULL) {
prune_one_dentry(dentry);
up_read(s_umount);
continue;
}
up_read(s_umount);
}
spin_unlock(&dentry->d_lock);
/* Cannot remove the first dentry, and it isn't appropriate
* to move it to the head of the list, so give up, and try
* later
*/
break;
}
spin_unlock(&dcache_lock);
}
Expand Down Expand Up @@ -630,7 +683,7 @@ void shrink_dcache_parent(struct dentry * parent)
int found;

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

/**
Expand All @@ -643,9 +696,10 @@ void shrink_dcache_parent(struct dentry * parent)
* done under dcache_lock.
*
*/
void shrink_dcache_anon(struct hlist_head *head)
void shrink_dcache_anon(struct super_block *sb)
{
struct hlist_node *lp;
struct hlist_head *head = &sb->s_anon;
int found;
do {
found = 0;
Expand All @@ -668,7 +722,7 @@ void shrink_dcache_anon(struct hlist_head *head)
}
}
spin_unlock(&dcache_lock);
prune_dcache(found);
prune_dcache(found, sb);
} while(found);
}

Expand All @@ -689,7 +743,7 @@ static int shrink_dcache_memory(int nr, gfp_t gfp_mask)
if (nr) {
if (!(gfp_mask & __GFP_FS))
return -1;
prune_dcache(nr);
prune_dcache(nr, NULL);
}
return (dentry_stat.nr_unused / 100) * sysctl_vfs_cache_pressure;
}
Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ void generic_shutdown_super(struct super_block *sb)
if (root) {
sb->s_root = NULL;
shrink_dcache_parent(root);
shrink_dcache_anon(&sb->s_anon);
shrink_dcache_anon(sb);
dput(root);
fsync_super(sb);
lock_super(sb);
Expand Down
2 changes: 1 addition & 1 deletion trunk/include/linux/dcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ extern struct dentry * d_alloc_anon(struct inode *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
extern void shrink_dcache_sb(struct super_block *);
extern void shrink_dcache_parent(struct dentry *);
extern void shrink_dcache_anon(struct hlist_head *);
extern void shrink_dcache_anon(struct super_block *);
extern int d_invalidate(struct dentry *);

/* only used at mount-time */
Expand Down

0 comments on commit ab98958

Please sign in to comment.