--- mm/slub.c | 95 ++++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 65 insertions(+), 30 deletions(-) Index: linux-2.6.21-rc5-mm4/mm/slub.c =================================================================== --- linux-2.6.21-rc5-mm4.orig/mm/slub.c 2007-04-08 19:08:38.000000000 -0700 +++ linux-2.6.21-rc5-mm4/mm/slub.c 2007-04-08 21:00:39.000000000 -0700 @@ -211,7 +211,10 @@ struct track { unsigned long when; /* When did the operation occur */ }; -struct track *get_track(struct kmem_cache *s, void *object, int alloc) +enum track_item { TRACK_ALLOC, TRACK_FREE }; + +struct track *get_track(struct kmem_cache *s, void *object, + enum track_item alloc) { struct track *p; @@ -224,7 +227,7 @@ struct track *get_track(struct kmem_cach } static void set_track(struct kmem_cache *s, void *object, - int alloc, void *addr) + enum track_item alloc, void *addr) { struct track *p; @@ -249,8 +252,8 @@ static void set_track(struct kmem_cache static void init_tracking(struct kmem_cache *s, void *object) { if (s->flags & SLAB_STORE_USER) { - set_track(s, object, 0, NULL); - set_track(s, object, 1, NULL); + set_track(s, object, TRACK_FREE, NULL); + set_track(s, object, TRACK_ALLOC, NULL); } } @@ -298,8 +301,8 @@ static void print_trailer(struct kmem_ca off = s->inuse; if (s->flags & SLAB_STORE_USER) { - print_track("Last alloc", get_track(s, p, 0)); - print_track("Last free ", get_track(s, p, 1)); + print_track("Last alloc", get_track(s, p, TRACK_ALLOC)); + print_track("Last free ", get_track(s, p, TRACK_FREE)); off += 2 * sizeof(struct track); } @@ -1212,7 +1215,7 @@ debug: if (!alloc_object_checks(s, page, object)) goto another_slab; if (s->flags & SLAB_STORE_USER) - set_tracking(s, object, 0); + set_tracking(s, object, TRACK_ALLOC); goto have_object; } @@ -1305,7 +1308,7 @@ void kmem_cache_free(struct kmem_cache * page = compound_head(page); if (unlikely(PageError(page) && (s->flags & SLAB_STORE_USER))) - set_tracking(s, x, 1); + set_tracking(s, x, TRACK_FREE); slab_free(s, page, x); } EXPORT_SYMBOL(kmem_cache_free); @@ -1926,7 +1929,7 @@ void kfree(const void *x) s = page->slab; if (unlikely(PageError(page) && (s->flags & SLAB_STORE_USER))) - set_tracking(s, (void *)x, 1); + set_tracking(s, (void *)x, TRACK_FREE); slab_free(s, page, (void *)x); } EXPORT_SYMBOL(kfree); @@ -2286,7 +2289,7 @@ void *__kmalloc_track_caller(size_t size object = kmem_cache_alloc(s, gfpflags); if (object && (s->flags & SLAB_STORE_USER)) - set_track(s, object, 0, caller); + set_track(s, object, TRACK_ALLOC, caller); return object; } @@ -2303,7 +2306,7 @@ void *__kmalloc_node_track_caller(size_t object = kmem_cache_alloc_node(s, gfpflags, node); if (object && (s->flags & SLAB_STORE_USER)) - set_track(s, object, 0, caller); + set_track(s, object, TRACK_ALLOC, caller); return object; } @@ -2356,10 +2359,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; } @@ -2429,22 +2434,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; } @@ -2461,10 +2469,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; @@ -2472,7 +2480,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)]; @@ -2483,11 +2491,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; @@ -2495,7 +2507,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); @@ -2504,22 +2516,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; } @@ -2871,7 +2906,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); @@ -2879,7 +2914,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);