Re: [PATCH] Per-superblock unused dentry LRU lists V3

From: Jan Blunck
Date: Tue May 30 2006 - 11:03:52 EST


> David Chinner <dgc@xxxxxxx> wrote:
>
> +/*
> + * Shrink the dentry LRU on a given superblock.
> + *
> + * If flags is non-zero, we need to do special processing based on
> + * which flags are set. This means we don't need to maintain multiple
> + * similar copies of this loop.
> + */
> +static void __shrink_dcache_sb(struct super_block *sb, int *count, int
> flags)
> +{
> + struct dentry *dentry;
> + int cnt = *count;
> +
> + spin_lock(&dcache_lock);
> + while (!list_empty(&sb->s_dentry_lru) && cnt--) {
> + dentry = list_entry(sb->s_dentry_lru.prev,
> + struct dentry, d_lru);
> + dentry_lru_del_init(dentry);
> + BUG_ON(dentry->d_sb != sb);
> + prefetch(sb->s_dentry_lru.prev);
> +
> + spin_lock(&dentry->d_lock);
> + /*
> + * We found an inuse dentry which was not removed from
> + * the LRU because of laziness during lookup. Do not free
> + * it - just keep it off the LRU list.
> + */
> + if (atomic_read(&dentry->d_count)) {
> + spin_unlock(&dentry->d_lock);
> + continue;
> + }
> + /*
> + * If we are honouring the DCACHE_REFERENCED flag and the
> + * dentry has this flag set, don't free it. Clear the flag
> + * and put it back on the LRU
> + */
> + if ((flags & DCACHE_REFERENCED) &&
> + (dentry->d_flags & DCACHE_REFERENCED)) {
> + dentry->d_flags &= ~DCACHE_REFERENCED;
> + dentry_lru_add(dentry);
> + spin_unlock(&dentry->d_lock);
> + continue;
> + }
> + prune_one_dentry(dentry);
> + }
> + spin_unlock(&dcache_lock);
> + *count = cnt;
> +}
> +
> /**
> * shrink_dcache_sb - shrink dcache for a superblock
> * @sb: superblock
> @@ -507,44 +529,9 @@ static void prune_dcache(int count, stru
> * is used to free the dcache before unmounting a file
> * system
> */
> -
> void shrink_dcache_sb(struct super_block * sb)
> {
> - struct list_head *tmp, *next;
> - struct dentry *dentry;
> -
> - /*
> - * Pass one ... move the dentries for the specified
> - * superblock to the most recent end of the unused list.
> - */
> - spin_lock(&dcache_lock);
> - list_for_each_safe(tmp, next, &dentry_unused) {
> - dentry = list_entry(tmp, struct dentry, d_lru);
> - if (dentry->d_sb != sb)
> - continue;
> - list_move(tmp, &dentry_unused);
> - }
> -
> - /*
> - * Pass two ... free the dentries for this superblock.
> - */
> -repeat:
> - list_for_each_safe(tmp, next, &dentry_unused) {
> - dentry = list_entry(tmp, struct dentry, d_lru);
> - if (dentry->d_sb != sb)
> - continue;
> - dentry_stat.nr_unused--;
> - list_del_init(tmp);
> - spin_lock(&dentry->d_lock);
> - if (atomic_read(&dentry->d_count)) {
> - spin_unlock(&dentry->d_lock);
> - continue;
> - }
> - prune_one_dentry(dentry);
> - cond_resched_lock(&dcache_lock);
> - goto repeat;
> - }
> - spin_unlock(&dcache_lock);
> + __shrink_dcache_sb(sb, &sb->s_dentry_lru_nr, 0);
> }

This doesn't prune all the dentries on the unused list. The parents of the
pruned dentries are added to the unused list. Therefore just shrinking
sb->s_dentry_lru_nr dentries isn't enough.

Jan
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/