> 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-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html