This is a multi-part message in MIME format. --------------050002090306000302070804 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi Andrew, I've hacked together a function that dumps all avaliable data about an slab object, based on a virtual address. It would be great if you could try it on your distcc server. The change to the page fault handler is just an example. Unfortunately it's not possible to check if kfree was already called - objects can be in too many intermediate caches. I'm printing the redzone data instead - should be enough to identify if it's a networking or DEBUG_PAGEALLOC bug. -- Manfred --------------050002090306000302070804 Content-Type: text/plain; name="patch-ptrinfo" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="patch-ptrinfo" // $Header$ // Kernel Version: // VERSION = 2 // PATCHLEVEL = 5 // SUBLEVEL = 69 // EXTRAVERSION = -mm7 arch/i386/Kconfig | 2 - arch/i386/mm/fault.c | 3 + include/linux/slab.h | 2 + mm/slab.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 3 deletions(-) diff -puN arch/i386/mm/fault.c~CONFIG_DEBUG_PAGEALLOC-extras arch/i386/mm/fault.c --- 25/arch/i386/mm/fault.c~CONFIG_DEBUG_PAGEALLOC-extras 2003-05-28 03:11:01.000000000 -0700 +++ 25-akpm/arch/i386/mm/fault.c 2003-05-28 03:11:02.000000000 -0700 @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -270,7 +271,9 @@ no_context: } #endif die("Oops", regs, error_code); + ptrinfo(address); bust_spinlocks(0); +for(;;); do_exit(SIGKILL); /* diff -puN mm/slab.c~CONFIG_DEBUG_PAGEALLOC-extras mm/slab.c --- 25/mm/slab.c~CONFIG_DEBUG_PAGEALLOC-extras 2003-05-28 03:11:02.000000000 -0700 +++ 25-akpm/mm/slab.c 2003-05-28 03:11:02.000000000 -0700 @@ -1006,6 +1006,10 @@ kmem_cache_create (const char *name, siz } #if FORCED_DEBUG +#ifdef CONFIG_DEBUG_PAGEALLOC + if (size < PAGE_SIZE-3*BYTES_PER_WORD && size > 128) + size = PAGE_SIZE-3*BYTES_PER_WORD; +#endif /* * Enable redzoning and last user accounting, except * - for caches with forced alignment: redzoning would violate the @@ -1429,8 +1433,6 @@ static void cache_init_objs (kmem_cache_ /* need to poison the objs? */ if (cachep->flags & SLAB_POISON) { poison_obj(cachep, objp, POISON_BEFORE); - if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep)) - unmap_pages(objp, cachep->objsize); } if (cachep->flags & SLAB_STORE_USER) { objlen -= BYTES_PER_WORD; @@ -1460,6 +1462,8 @@ static void cache_init_objs (kmem_cache_ slab_error(cachep, "constructor overwrote the" " start of an object"); } + if ((cachep->objsize % PAGE_SIZE) == 0 && OFF_SLAB(cachep) && cachep->flags & SLAB_POISON) + unmap_pages(objp, cachep->objsize); #else if (cachep->ctor) cachep->ctor(objp, cachep, ctor_flags); @@ -1676,6 +1680,7 @@ static inline void check_slabp(kmem_cach for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) { entries++; BUG_ON(entries > cachep->num); + BUG_ON(i < 0 || i >= cachep->num); } BUG_ON(entries != cachep->num - slabp->inuse); #endif @@ -2690,3 +2695,71 @@ unsigned int ksize(const void *objp) return size; } +void ptrinfo(unsigned long addr) +{ + struct page *page; + + printk("Dumping data about address %p.\n", (void*)addr); + if (!virt_addr_valid((void*)addr)) { + printk("virt addr invalid.\n"); + return; + } + do { + pgd_t *pgd = pgd_offset_k(addr); + pmd_t *pmd; + if (pgd_none(*pgd)) { + printk("No pgd.\n"); + break; + } + pmd = pmd_offset(pgd, addr); + if (pmd_none(*pmd)) { + printk("No pmd.\n"); + break; + } +#ifdef CONFIG_X86 + if (pmd_large(*pmd)) { + printk("Large page.\n"); + break; + } +#endif + printk("normal page, pte_val 0x%llx\n", + (unsigned long long)pte_val(*pte_offset_kernel(pmd, addr))); + } while(0); + + page = virt_to_page((void*)addr); + printk("struct page at %p, flags %lxh.\n", page, page->flags); + if (PageSlab(page)) { + kmem_cache_t *c; + struct slab *s; + unsigned long flags; + int objnr; + void *objp; + + c = GET_PAGE_CACHE(page); + printk("belongs to cache %s.\n",c->name); + + spin_lock_irqsave(&c->spinlock, flags); + s = GET_PAGE_SLAB(page); + printk("slabp %p with %d inuse objects (from %d).\n", + s, s->inuse, c->num); + check_slabp(c,s); + + objnr = (addr-(unsigned long)s->s_mem)/c->objsize; + objp = s->s_mem+c->objsize*objnr; + printk("points into object no %d, starting at %p, len %d.\n", + objnr, objp, c->objsize); + if (objnr >= c->num) { + printk("Bad obj number.\n"); + } else { +#ifdef CONFIG_DEBUG_PAGEALLOC + map_pages(objp, c->objsize); +#endif + printk("redzone: %lxh/%lxh/%lxh.\n", + ((unsigned long*)objp)[0], + ((unsigned long*)(objp+c->objsize))[-2], + ((unsigned long*)(objp+c->objsize))[-1]); + } + spin_unlock_irqrestore(&c->spinlock, flags); + + } +} diff -puN include/linux/slab.h~CONFIG_DEBUG_PAGEALLOC-extras include/linux/slab.h --- 25/include/linux/slab.h~CONFIG_DEBUG_PAGEALLOC-extras 2003-05-28 03:11:02.000000000 -0700 +++ 25-akpm/include/linux/slab.h 2003-05-28 03:11:02.000000000 -0700 @@ -80,6 +80,8 @@ extern kmem_cache_t *signal_cachep; extern kmem_cache_t *sighand_cachep; extern kmem_cache_t *bio_cachep; +void ptrinfo(unsigned long addr); + #endif /* __KERNEL__ */ #endif /* _LINUX_SLAB_H */ diff -puN arch/i386/Kconfig~CONFIG_DEBUG_PAGEALLOC-extras arch/i386/Kconfig --- 25/arch/i386/Kconfig~CONFIG_DEBUG_PAGEALLOC-extras 2003-05-28 03:11:02.000000000 -0700 +++ 25-akpm/arch/i386/Kconfig 2003-05-28 03:11:02.000000000 -0700 @@ -1561,7 +1561,7 @@ config SPINLINE config DEBUG_PAGEALLOC bool "Page alloc debugging" - depends on DEBUG_KERNEL + depends on DEBUG_SLAB help Unmap pages from the kernel linear mapping after free_pages(). This results in a large slowdown, but helps to find certain types _