aboutsummaryrefslogtreecommitdiffstats
path: root/mm/slub.c
diff options
context:
space:
mode:
authorChristoph Lameter <clameter@sgi.com>2007-05-06 17:49:43 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:12:54 -0400
commit53e15af03be4fdaaf20802d78f141487d7272985 (patch)
treed930a2240a9bb28187387377a699b2bf57ea579a /mm/slub.c
parent643b113849d8faa68c9f01c3c9d929bfbffd50bd (diff)
slub: validation of slabs (metadata and guard zones)
This enables validation of slab. Validation means that all objects are checked to see if there are redzone violations, if padding has been overwritten or any pointers have been corrupted. Also checks the consistency of slab counters. Validation enables the detection of metadata corruption without the kernel having to execute code that actually uses (allocs/frees) and object. It allows one to make sure that the slab metainformation and the guard values around an object have not been compromised. A single slabcache can be checked by writing a 1 to the "validate" file. i.e. echo 1 >/sys/slab/kmalloc-128/validate or use the slabinfo tool to check all slabs slabinfo -v Error messages will show up in the syslog. Note that validation can only reach slabs that are on a list. This means that we are usually restricted to partial slabs and active slabs unless SLAB_STORE_USER is active which will build a full slab list and allows validation of slabs that are fully in use. Booting with "slub_debug" set will enable SLAB_STORE_USER and then full diagnostic are available. Note that we attempt to push cpu slabs back to the lists when we start the check. If the cpu slab is reactivated before we get to it (another processor grabs it before we get to it) then it cannot be checked. Signed-off-by: Christoph Lameter <clameter@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/slub.c')
-rw-r--r--mm/slub.c113
1 files changed, 110 insertions, 3 deletions
diff --git a/mm/slub.c b/mm/slub.c
index c4f40d373d1e..69ee7f807e84 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -670,8 +670,6 @@ static void add_full(struct kmem_cache *s, struct page *page)
670 670
671 VM_BUG_ON(!irqs_disabled()); 671 VM_BUG_ON(!irqs_disabled());
672 672
673 VM_BUG_ON(!irqs_disabled());
674
675 if (!(s->flags & SLAB_STORE_USER)) 673 if (!(s->flags & SLAB_STORE_USER))
676 return; 674 return;
677 675
@@ -2551,6 +2549,99 @@ void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags,
2551 2549
2552#ifdef CONFIG_SYSFS 2550#ifdef CONFIG_SYSFS
2553 2551
2552static int validate_slab(struct kmem_cache *s, struct page *page)
2553{
2554 void *p;
2555 void *addr = page_address(page);
2556 unsigned long map[BITS_TO_LONGS(s->objects)];
2557
2558 if (!check_slab(s, page) ||
2559 !on_freelist(s, page, NULL))
2560 return 0;
2561
2562 /* Now we know that a valid freelist exists */
2563 bitmap_zero(map, s->objects);
2564
2565 for(p = page->freelist; p; p = get_freepointer(s, p)) {
2566 set_bit((p - addr) / s->size, map);
2567 if (!check_object(s, page, p, 0))
2568 return 0;
2569 }
2570
2571 for(p = addr; p < addr + s->objects * s->size; p += s->size)
2572 if (!test_bit((p - addr) / s->size, map))
2573 if (!check_object(s, page, p, 1))
2574 return 0;
2575 return 1;
2576}
2577
2578static void validate_slab_slab(struct kmem_cache *s, struct page *page)
2579{
2580 if (slab_trylock(page)) {
2581 validate_slab(s, page);
2582 slab_unlock(page);
2583 } else
2584 printk(KERN_INFO "SLUB %s: Skipped busy slab 0x%p\n",
2585 s->name, page);
2586
2587 if (s->flags & DEBUG_DEFAULT_FLAGS) {
2588 if (!PageError(page))
2589 printk(KERN_ERR "SLUB %s: PageError not set "
2590 "on slab 0x%p\n", s->name, page);
2591 } else {
2592 if (PageError(page))
2593 printk(KERN_ERR "SLUB %s: PageError set on "
2594 "slab 0x%p\n", s->name, page);
2595 }
2596}
2597
2598static int validate_slab_node(struct kmem_cache *s, struct kmem_cache_node *n)
2599{
2600 unsigned long count = 0;
2601 struct page *page;
2602 unsigned long flags;
2603
2604 spin_lock_irqsave(&n->list_lock, flags);
2605
2606 list_for_each_entry(page, &n->partial, lru) {
2607 validate_slab_slab(s, page);
2608 count++;
2609 }
2610 if (count != n->nr_partial)
2611 printk(KERN_ERR "SLUB %s: %ld partial slabs counted but "
2612 "counter=%ld\n", s->name, count, n->nr_partial);
2613
2614 if (!(s->flags & SLAB_STORE_USER))
2615 goto out;
2616
2617 list_for_each_entry(page, &n->full, lru) {
2618 validate_slab_slab(s, page);
2619 count++;
2620 }
2621 if (count != atomic_long_read(&n->nr_slabs))
2622 printk(KERN_ERR "SLUB: %s %ld slabs counted but "
2623 "counter=%ld\n", s->name, count,
2624 atomic_long_read(&n->nr_slabs));
2625
2626out:
2627 spin_unlock_irqrestore(&n->list_lock, flags);
2628 return count;
2629}
2630
2631static unsigned long validate_slab_cache(struct kmem_cache *s)
2632{
2633 int node;
2634 unsigned long count = 0;
2635
2636 flush_all(s);
2637 for_each_online_node(node) {
2638 struct kmem_cache_node *n = get_node(s, node);
2639
2640 count += validate_slab_node(s, n);
2641 }
2642 return count;
2643}
2644
2554static unsigned long count_partial(struct kmem_cache_node *n) 2645static unsigned long count_partial(struct kmem_cache_node *n)
2555{ 2646{
2556 unsigned long flags; 2647 unsigned long flags;
@@ -2680,7 +2771,6 @@ struct slab_attribute {
2680 static struct slab_attribute _name##_attr = \ 2771 static struct slab_attribute _name##_attr = \
2681 __ATTR(_name, 0644, _name##_show, _name##_store) 2772 __ATTR(_name, 0644, _name##_show, _name##_store)
2682 2773
2683
2684static ssize_t slab_size_show(struct kmem_cache *s, char *buf) 2774static ssize_t slab_size_show(struct kmem_cache *s, char *buf)
2685{ 2775{
2686 return sprintf(buf, "%d\n", s->size); 2776 return sprintf(buf, "%d\n", s->size);
@@ -2886,6 +2976,22 @@ static ssize_t store_user_store(struct kmem_cache *s,
2886} 2976}
2887SLAB_ATTR(store_user); 2977SLAB_ATTR(store_user);
2888 2978
2979static ssize_t validate_show(struct kmem_cache *s, char *buf)
2980{
2981 return 0;
2982}
2983
2984static ssize_t validate_store(struct kmem_cache *s,
2985 const char *buf, size_t length)
2986{
2987 if (buf[0] == '1')
2988 validate_slab_cache(s);
2989 else
2990 return -EINVAL;
2991 return length;
2992}
2993SLAB_ATTR(validate);
2994
2889#ifdef CONFIG_NUMA 2995#ifdef CONFIG_NUMA
2890static ssize_t defrag_ratio_show(struct kmem_cache *s, char *buf) 2996static ssize_t defrag_ratio_show(struct kmem_cache *s, char *buf)
2891{ 2997{
@@ -2925,6 +3031,7 @@ static struct attribute * slab_attrs[] = {
2925 &red_zone_attr.attr, 3031 &red_zone_attr.attr,
2926 &poison_attr.attr, 3032 &poison_attr.attr,
2927 &store_user_attr.attr, 3033 &store_user_attr.attr,
3034 &validate_attr.attr,
2928#ifdef CONFIG_ZONE_DMA 3035#ifdef CONFIG_ZONE_DMA
2929 &cache_dma_attr.attr, 3036 &cache_dma_attr.attr,
2930#endif 3037#endif