--- mm/slub.c | 95 ++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 30 deletions(-) Index: linux-2.6.21-rc6-mm1/mm/slub.c =================================================================== --- linux-2.6.21-rc6-mm1.orig/mm/slub.c 2007-04-09 15:34:14.000000000 -0700 +++ linux-2.6.21-rc6-mm1/mm/slub.c 2007-04-09 15:34:44.000000000 -0700 @@ -2357,10 +2357,12 @@ static int validate_slab_node(struct kme validate_slab_slab(s, page); count++; } + printk("partial=%d\n",count); list_for_each_entry(page, &n->full, lru) { validate_slab_slab(s, page); count++; } + printk("partial+full=%d\n",count); spin_unlock_irqrestore(&n->list_lock, flags); return count; } @@ -2430,22 +2432,25 @@ static int alloc_loc_track(struct loc_tr static int add_location(struct loc_track *t, struct kmem_cache *s, void *addr) { - unsigned long start, end; + long start, end, pos; struct location *l; + void *caddr; start = 0; end = t->count; for(;;) { - unsigned long pos = start + (end - start / 2); - void *caddr; + pos = start + (end - start + 1) / 2; - if (pos == start) + /* + * There is nothing at "end". If we end up there + * we need to add something to before end. + */ + if (pos == end) break; caddr = t->loc[pos].addr; if (addr == caddr) { - /* Found. Increment number */ t->loc[pos].count++; return 1; } @@ -2462,10 +2467,10 @@ static int add_location(struct loc_track if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max)) return 0; - l = t->loc + end; - if (end < t->count) + l = t->loc + pos; + if (pos < t->count) memmove(l + 1, l, - (t->count - end) * sizeof(struct location)); + (t->count - pos) * sizeof(struct location)); t->count++; l->count = 1; l->addr = addr; @@ -2473,7 +2478,7 @@ static int add_location(struct loc_track } static void process_slab(struct loc_track *t, struct kmem_cache *s, - struct page *page, int alloc) + struct page *page, enum track_item alloc) { void *addr = page_address(page); unsigned long map[BITS_TO_LONGS(s->objects)]; @@ -2484,11 +2489,15 @@ static void process_slab(struct loc_trac set_bit((p - addr) / s->size, map); for(p = addr; p < addr + s->objects * s->size; p += s->size) - if (!test_bit((p - addr) / s->size, map)) - add_location(t, s, get_track(s, p, alloc)->addr); + if (!test_bit((p - addr) / s->size, map)) { + void *addr = get_track(s, p, alloc)->addr; + + add_location(t, s, addr); + } } -static int list_locations(struct kmem_cache *s, char *buf, int alloc) +static int list_locations(struct kmem_cache *s, char *buf, + enum track_item alloc) { int n = 0; unsigned long i; @@ -2496,7 +2505,7 @@ static int list_locations(struct kmem_ca int node; t.count = 0; - t.max =0; + t.max = 0; /* Push back cpu slabs */ flush_all(s); @@ -2505,22 +2514,45 @@ static int list_locations(struct kmem_ca struct kmem_cache_node *n = get_node(s, node); unsigned long flags; struct page *page; + unsigned long slab_count = 0; + + if (!atomic_read(&n->nr_slabs)) + continue; spin_lock_irqsave(&n->list_lock, flags); - list_for_each_entry(page, &n->partial, lru) + list_for_each_entry(page, &n->partial, lru) { process_slab(&t, s, page, alloc); - list_for_each_entry(page, &n->full, lru) + slab_count++; + } + if (slab_count != n->nr_partial) + printk(KERN_ERR "partial mismatch nr_partial=%ld actual=%ld\n", + n->nr_partial, slab_count); + list_for_each_entry(page, &n->full, lru) { process_slab(&t, s, page, alloc); + slab_count++; + } + if (slab_count != atomic_read(&n->nr_slabs)) + printk(KERN_ERR "counting mismatch counter=%ld actual=%ld\n", + atomic_read(&n->nr_slabs), slab_count); spin_unlock_irqrestore(&n->list_lock, flags); } for (i = 0; i < t.count; i++) { - n += sprintf(buf + n, "%ld ", t.loc[i].count); - n += sprint_symbol(buf + n, (unsigned long)t.loc[i].addr); + void *addr = t.loc[i].addr; + + if (n > PAGE_SIZE - 100) + break; + n += sprintf(buf + n, "%7ld ", t.loc[i].count); + if (addr) + n += sprint_symbol(buf + n, (unsigned long)t.loc[i].addr); + else + n += sprintf(buf + n, ""); n += sprintf(buf + n, "\n"); } free_loc_track(&t); + if (!t.count) + n += sprintf(buf, "No data\n"); return n; } @@ -2872,7 +2904,7 @@ static ssize_t alloc_calls_show(struct k { if (!(s->flags & SLAB_STORE_USER)) return -ENOSYS; - return list_locations(s, buf, 1); + return list_locations(s, buf, TRACK_ALLOC); } SLAB_ATTR_RO(alloc_calls); @@ -2880,7 +2912,7 @@ static ssize_t free_calls_show(struct km { if (!(s->flags & SLAB_STORE_USER)) return -ENOSYS; - return list_locations(s, buf, 0); + return list_locations(s, buf, TRACK_FREE); } SLAB_ATTR_RO(free_calls);