--- fs/dcache.c | 55 ++++++++++++++++++++++++++++++++++++----------------- include/linux/mm.h | 2 - mm/slub.c | 31 ++++++++++++++++++++++++++--- mm/vmscan.c | 2 - 4 files changed, 67 insertions(+), 23 deletions(-) Index: linux-2.6/fs/dcache.c =================================================================== --- linux-2.6.orig/fs/dcache.c 2007-08-02 23:23:48.000000000 -0700 +++ linux-2.6/fs/dcache.c 2007-08-02 23:54:19.000000000 -0700 @@ -135,7 +135,6 @@ static struct dentry *d_kill(struct dent list_del(&dentry->d_u.d_child); dentry_stat.nr_dentry--; /* For d_free, below */ - dentry->d_flags &= ~DCACHE_ENTRY_VALID; /*drops the locks, at that point nobody can reach this dentry */ dentry_iput(dentry); parent = dentry->d_parent; @@ -951,7 +950,7 @@ struct dentry *d_alloc(struct dentry * p if (parent) list_add(&dentry->d_u.d_child, &parent->d_subdirs); dentry_stat.nr_dentry++; - dentry->d_flags = DCACHE_UNHASHED | DCACHE_ENTRY_VALID; + dentry->d_flags = DCACHE_UNHASHED; spin_unlock(&dcache_lock); return dentry; @@ -2117,36 +2116,52 @@ static void *get_dentries(struct kmem_ca { struct dentry *dentry; int i; - unsigned long abort = 0; spin_lock(&dcache_lock); for (i = 0; i < nr; i++) { dentry = v[i]; /* - * Do not try to evict dentries in slab with a root - * entry. + * We cannot evict an unreachable entry. An entry is + * reachable if its either hashed or on the lru. */ - if (abort || IS_ROOT(dentry)) { - abort = 1; -zap_entry: + if (d_unhashed(dentry) && list_empty(&dentry->d_lru)) { v[i] = NULL; continue; } /* - * if DCACHE_ENTRY_VALID is not set then the dentry - * may be already in the process of being freed. + * FIXME: d_flags says hashed but hlist says unhashed! + * d_invalidate will fail on these. */ - if (!(dentry->d_flags & DCACHE_ENTRY_VALID)) - goto zap_entry; + if (!d_unhashed(dentry) && hlist_unhashed(&dentry->d_hash)) { + v[i] = NULL; + continue; + } dget_locked(dentry); } spin_unlock(&dcache_lock); - return (void *)abort; + return 0; } +int bad_dentry(struct dentry *d) +{ + if (d_unhashed(d)) + return 0; + + if (d->d_hash.pprev) + return 0; + + printk("Bad dentry %p: flags=%x count=%d name=%p/%s inode=%p " + "is_root=%d parent=%p dop=%p sb=%p\n", + d, d->d_flags, atomic_read(&d->d_count), + d->d_name.name, d->d_name.name, + d->d_inode, IS_ROOT(d), + d->d_parent, d->d_op, d->d_sb); + dump_stack(); + return 1; +} /* * Slab has dropped all the locks. Get rid of the * refcount we obtained earlier and also rid of the @@ -2155,7 +2170,7 @@ zap_entry: static void kick_dentries(struct kmem_cache *s, int nr, void **v, void *private) { struct dentry *dentry; - unsigned long abort = (unsigned long)private; + unsigned long abort = 0; int i; /* @@ -2165,8 +2180,12 @@ static void kick_dentries(struct kmem_ca for (i = 0; i < nr; i++) { dentry = v[i]; - if (dentry) + if (dentry) { + if (bad_dentry(dentry)) + continue; + d_invalidate(dentry); + } } } @@ -2185,6 +2204,7 @@ static void kick_dentries(struct kmem_ca spin_lock(&dentry->d_lock); if (atomic_read(&dentry->d_count) > 1) { + printk("dentry %p refcout increased\n", dentry); /* * Reference count was increased. This means that we * cannot free one object which makes it impossible @@ -2222,8 +2242,9 @@ static void __init dcache_init(unsigned { int loop; - dentry_cache = KMEM_CACHE(dentry, - SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD); + dentry_cache = kmem_cache_create("dentry", sizeof(struct dentry), 0, + SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD, + dentry_init_once); register_shrinker(&dcache_shrinker); kmem_cache_setup_defrag(dentry_cache, get_dentries, kick_dentries); Index: linux-2.6/include/linux/mm.h =================================================================== --- linux-2.6.orig/include/linux/mm.h 2007-08-02 23:23:48.000000000 -0700 +++ linux-2.6/include/linux/mm.h 2007-08-02 23:24:15.000000000 -0700 @@ -290,7 +290,7 @@ static inline int put_page_testzero(stru */ static inline int get_page_unless_zero(struct page *page) { - VM_BUG_ON(PageCompound(page)); + VM_BUG_ON(PageTail(page)); return atomic_inc_not_zero(&page->_count); } Index: linux-2.6/mm/slub.c =================================================================== --- linux-2.6.orig/mm/slub.c 2007-08-02 23:24:10.000000000 -0700 +++ linux-2.6/mm/slub.c 2007-08-02 23:37:56.000000000 -0700 @@ -107,6 +107,8 @@ #define SLABDEBUG 0 #endif +#define SLABRECLAIMABLE (1 << PG_dirty) + static inline int SlabFrozen(struct page *page) { return page->flags & FROZEN; @@ -137,6 +139,21 @@ static inline void ClearSlabDebug(struct page->flags &= ~SLABDEBUG; } +static inline int SlabReclaimable(struct page *page) +{ + return page->flags & SLABRECLAIMABLE; +} + +static inline void SetSlabReclaimable(struct page *page) +{ + page->flags |= SLABRECLAIMABLE; +} + +static inline void ClearSlabReclaimable(struct page *page) +{ + page->flags &= ~SLABRECLAIMABLE; +} + /* * Issues still to be resolved: * @@ -1126,6 +1143,8 @@ static struct page *new_slab(struct kmem if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | SLAB_TRACE)) SetSlabDebug(page); + if (s->kick) + SetSlabReclaimable(page); out: if (flags & __GFP_WAIT) @@ -1183,6 +1202,7 @@ static void discard_slab(struct kmem_cac atomic_long_dec(&n->nr_slabs); reset_page_mapcount(page); __ClearPageSlab(page); + ClearSlabReclaimable(page); free_slab(s, page); } @@ -2515,8 +2535,6 @@ static int __kmem_cache_vacate(struct km void *private; unsigned long flags; - BUG_ON(!PageSlab(page)); - local_irq_save(flags); slab_lock(page); @@ -2575,7 +2593,7 @@ int kmem_cache_isolate_slab(struct page struct kmem_cache *s; int rc = -ENOENT; - if (!PageSlab(page)) + if (!PageSlab(page) || !SlabReclaimable(page)) return rc; /* @@ -2600,6 +2618,12 @@ int kmem_cache_isolate_slab(struct page if (!PageSlab(page) || !s->kick || SlabFrozen(page) || !page->inuse) { slab_unlock(page); put_page(page); + printk("kmc_isolate_page(%p) %s %lx kick=%p inuse=%d\n", + page, + PageSlab(page) ? s->name : "?", + page->flags, + PageSlab(page) ? s->kick : NULL, + page->inuse); goto out; } @@ -2628,7 +2652,6 @@ int kmem_cache_isolate_slab(struct page rc = 0; out: local_irq_restore(flags); - printk("kmem_cache_isolate_page(%p) returns %d\n", page, rc); return rc; } Index: linux-2.6/mm/vmscan.c =================================================================== --- linux-2.6.orig/mm/vmscan.c 2007-08-02 23:24:10.000000000 -0700 +++ linux-2.6/mm/vmscan.c 2007-08-02 23:24:18.000000000 -0700 @@ -736,7 +736,7 @@ static unsigned long isolate_lru_pages(u default: if (slab_pages && kmem_cache_isolate_slab(cursor_page) == 0) - list_move(&cursor_page->lru, + list_add(&cursor_page->lru, slab_pages); break; }