

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            |   73 +++++++++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 77 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-23 19:28:56.000000000 -0700
+++ 25-akpm/arch/i386/mm/fault.c	2003-05-23 19:28:56.000000000 -0700
@@ -13,6 +13,7 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/interrupt.h>
@@ -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-23 19:28:56.000000000 -0700
+++ 25-akpm/mm/slab.c	2003-05-23 20:21:07.000000000 -0700
@@ -990,6 +990,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
@@ -1413,8 +1417,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;
@@ -1444,6 +1446,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);
@@ -1660,6 +1664,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
@@ -2674,3 +2679,67 @@ 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;
+		}
+		if (pmd_large(*pmd)) {
+			printk("Large page.\n");
+			break;
+		}
+		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-23 19:28:56.000000000 -0700
+++ 25-akpm/include/linux/slab.h	2003-05-23 20:21:07.000000000 -0700
@@ -78,6 +78,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-23 19:28:56.000000000 -0700
+++ 25-akpm/arch/i386/Kconfig	2003-05-23 20:21:08.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

_
