]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - mm/slub.c
slub: Add lock release annotation
[net-next-2.6.git] / mm / slub.c
index c1add106c4317f15743e10ab26bc340cdd5f0c27..118422e220f09ec59160f5527aef4c2c82672dbb 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -209,6 +209,7 @@ static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p)
                                                        { return 0; }
 static inline void sysfs_slab_remove(struct kmem_cache *s)
 {
+       kfree(s->name);
        kfree(s);
 }
 
@@ -232,11 +233,7 @@ int slab_is_available(void)
 
 static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
 {
-#ifdef CONFIG_NUMA
        return s->node[node];
-#else
-       return &s->local_node;
-#endif
 }
 
 /* Verify that a pointer has an address that is valid within a slab page */
@@ -493,7 +490,7 @@ static void slab_err(struct kmem_cache *s, struct page *page, char *fmt, ...)
        dump_stack();
 }
 
-static void init_object(struct kmem_cache *s, void *object, int active)
+static void init_object(struct kmem_cache *s, void *object, u8 val)
 {
        u8 *p = object;
 
@@ -503,9 +500,7 @@ static void init_object(struct kmem_cache *s, void *object, int active)
        }
 
        if (s->flags & SLAB_RED_ZONE)
-               memset(p + s->objsize,
-                       active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE,
-                       s->inuse - s->objsize);
+               memset(p + s->objsize, val, s->inuse - s->objsize);
 }
 
 static u8 *check_bytes(u8 *start, unsigned int value, unsigned int bytes)
@@ -640,17 +635,14 @@ static int slab_pad_check(struct kmem_cache *s, struct page *page)
 }
 
 static int check_object(struct kmem_cache *s, struct page *page,
-                                       void *object, int active)
+                                       void *object, u8 val)
 {
        u8 *p = object;
        u8 *endobject = object + s->objsize;
 
        if (s->flags & SLAB_RED_ZONE) {
-               unsigned int red =
-                       active ? SLUB_RED_ACTIVE : SLUB_RED_INACTIVE;
-
                if (!check_bytes_and_report(s, page, object, "Redzone",
-                       endobject, red, s->inuse - s->objsize))
+                       endobject, val, s->inuse - s->objsize))
                        return 0;
        } else {
                if ((s->flags & SLAB_POISON) && s->objsize < s->inuse) {
@@ -660,7 +652,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
        }
 
        if (s->flags & SLAB_POISON) {
-               if (!active && (s->flags & __OBJECT_POISON) &&
+               if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) &&
                        (!check_bytes_and_report(s, page, p, "Poison", p,
                                        POISON_FREE, s->objsize - 1) ||
                         !check_bytes_and_report(s, page, p, "Poison",
@@ -672,7 +664,7 @@ static int check_object(struct kmem_cache *s, struct page *page,
                check_pad_bytes(s, page, p);
        }
 
-       if (!s->offset && active)
+       if (!s->offset && val == SLUB_RED_ACTIVE)
                /*
                 * Object and freepointer overlap. Cannot check
                 * freepointer while object is allocated.
@@ -870,7 +862,7 @@ static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
         * dilemma by deferring the increment of the count during
         * bootstrap (see early_kmem_cache_node_alloc).
         */
-       if (!NUMA_BUILD || n) {
+       if (n) {
                atomic_long_inc(&n->nr_slabs);
                atomic_long_add(objects, &n->total_objects);
        }
@@ -890,7 +882,7 @@ static void setup_object_debug(struct kmem_cache *s, struct page *page,
        if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON)))
                return;
 
-       init_object(s, object, 0);
+       init_object(s, object, SLUB_RED_INACTIVE);
        init_tracking(s, object);
 }
 
@@ -910,14 +902,14 @@ static noinline int alloc_debug_processing(struct kmem_cache *s, struct page *pa
                goto bad;
        }
 
-       if (!check_object(s, page, object, 0))
+       if (!check_object(s, page, object, SLUB_RED_INACTIVE))
                goto bad;
 
        /* Success perform special debug activities for allocs */
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_ALLOC, addr);
        trace(s, page, object, 1);
-       init_object(s, object, 1);
+       init_object(s, object, SLUB_RED_ACTIVE);
        return 1;
 
 bad:
@@ -950,7 +942,7 @@ static noinline int free_debug_processing(struct kmem_cache *s,
                goto fail;
        }
 
-       if (!check_object(s, page, object, 1))
+       if (!check_object(s, page, object, SLUB_RED_ACTIVE))
                return 0;
 
        if (unlikely(s != page->slab)) {
@@ -974,7 +966,7 @@ static noinline int free_debug_processing(struct kmem_cache *s,
        if (s->flags & SLAB_STORE_USER)
                set_track(s, object, TRACK_FREE, addr);
        trace(s, page, object, 0);
-       init_object(s, object, 0);
+       init_object(s, object, SLUB_RED_INACTIVE);
        return 1;
 
 fail:
@@ -1078,7 +1070,7 @@ static inline int free_debug_processing(struct kmem_cache *s,
 static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
                        { return 1; }
 static inline int check_object(struct kmem_cache *s, struct page *page,
-                       void *object, int active) { return 1; }
+                       void *object, u8 val) { return 1; }
 static inline void add_full(struct kmem_cache_node *n, struct page *page) {}
 static inline unsigned long kmem_cache_flags(unsigned long objsize,
        unsigned long flags, const char *name,
@@ -1238,7 +1230,7 @@ static void __free_slab(struct kmem_cache *s, struct page *page)
                slab_pad_check(s, page);
                for_each_object(p, s, page_address(page),
                                                page->objects)
-                       check_object(s, page, p, 0);
+                       check_object(s, page, p, SLUB_RED_INACTIVE);
        }
 
        kmemcheck_free_shadow(page, compound_order(page));
@@ -1318,13 +1310,19 @@ static void add_partial(struct kmem_cache_node *n,
        spin_unlock(&n->list_lock);
 }
 
+static inline void __remove_partial(struct kmem_cache_node *n,
+                                       struct page *page)
+{
+       list_del(&page->lru);
+       n->nr_partial--;
+}
+
 static void remove_partial(struct kmem_cache *s, struct page *page)
 {
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
 
        spin_lock(&n->list_lock);
-       list_del(&page->lru);
-       n->nr_partial--;
+       __remove_partial(n, page);
        spin_unlock(&n->list_lock);
 }
 
@@ -1337,8 +1335,7 @@ static inline int lock_and_freeze_slab(struct kmem_cache_node *n,
                                                        struct page *page)
 {
        if (slab_trylock(page)) {
-               list_del(&page->lru);
-               n->nr_partial--;
+               __remove_partial(n, page);
                __SetPageSlubFrozen(page);
                return 1;
        }
@@ -1449,6 +1446,7 @@ static struct page *get_partial(struct kmem_cache *s, gfp_t flags, int node)
  * On exit the slab lock will have been dropped.
  */
 static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
+       __releases(bitlock)
 {
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
 
@@ -1491,6 +1489,7 @@ static void unfreeze_slab(struct kmem_cache *s, struct page *page, int tail)
  * Remove the cpu slab
  */
 static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
+       __releases(bitlock)
 {
        struct page *page = c->page;
        int tail = 1;
@@ -2111,7 +2110,6 @@ static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
        return s->cpu_slab != NULL;
 }
 
-#ifdef CONFIG_NUMA
 static struct kmem_cache *kmem_cache_node;
 
 /*
@@ -2147,7 +2145,7 @@ static void early_kmem_cache_node_alloc(int node)
        page->inuse++;
        kmem_cache_node->node[node] = n;
 #ifdef CONFIG_SLUB_DEBUG
-       init_object(kmem_cache_node, n, 1);
+       init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
        init_tracking(kmem_cache_node, n);
 #endif
        init_kmem_cache_node(n, kmem_cache_node);
@@ -2201,17 +2199,6 @@ static int init_kmem_cache_nodes(struct kmem_cache *s)
        }
        return 1;
 }
-#else
-static void free_kmem_cache_nodes(struct kmem_cache *s)
-{
-}
-
-static int init_kmem_cache_nodes(struct kmem_cache *s)
-{
-       init_kmem_cache_node(&s->local_node, s);
-       return 1;
-}
-#endif
 
 static void set_min_partial(struct kmem_cache *s, unsigned long min)
 {
@@ -2448,9 +2435,8 @@ static void list_slab_objects(struct kmem_cache *s, struct page *page,
 #ifdef CONFIG_SLUB_DEBUG
        void *addr = page_address(page);
        void *p;
-       long *map = kzalloc(BITS_TO_LONGS(page->objects) * sizeof(long),
-                           GFP_ATOMIC);
-
+       unsigned long *map = kzalloc(BITS_TO_LONGS(page->objects) *
+                                    sizeof(long), GFP_ATOMIC);
        if (!map)
                return;
        slab_err(s, page, "%s", text);
@@ -2482,9 +2468,8 @@ static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n)
        spin_lock_irqsave(&n->list_lock, flags);
        list_for_each_entry_safe(page, h, &n->partial, lru) {
                if (!page->inuse) {
-                       list_del(&page->lru);
+                       __remove_partial(n, page);
                        discard_slab(s, page);
-                       n->nr_partial--;
                } else {
                        list_slab_objects(s, page,
                                "Objects remaining on kmem_cache_close()");
@@ -2842,8 +2827,7 @@ int kmem_cache_shrink(struct kmem_cache *s)
                                 * may have freed the last object and be
                                 * waiting to release the slab.
                                 */
-                               list_del(&page->lru);
-                               n->nr_partial--;
+                               __remove_partial(n, page);
                                slab_unlock(page);
                                discard_slab(s, page);
                        } else {
@@ -2909,7 +2893,7 @@ static void slab_mem_offline_callback(void *arg)
                        BUG_ON(slabs_node(s, offline_node));
 
                        s->node[offline_node] = NULL;
-                       kmem_cache_free(kmalloc_caches, n);
+                       kmem_cache_free(kmem_cache_node, n);
                }
        }
        up_read(&slub_lock);
@@ -2942,7 +2926,7 @@ static int slab_mem_going_online_callback(void *arg)
                 *      since memory is not yet available from the node that
                 *      is brought up.
                 */
-               n = kmem_cache_alloc(kmalloc_caches, GFP_KERNEL);
+               n = kmem_cache_alloc(kmem_cache_node, GFP_KERNEL);
                if (!n) {
                        ret = -ENOMEM;
                        goto out;
@@ -3022,8 +3006,6 @@ void __init kmem_cache_init(void)
        int caches = 0;
        struct kmem_cache *temp_kmem_cache;
        int order;
-
-#ifdef CONFIG_NUMA
        struct kmem_cache *temp_kmem_cache_node;
        unsigned long kmalloc_size;
 
@@ -3047,12 +3029,6 @@ void __init kmem_cache_init(void)
                0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
 
        hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
-#else
-       /* Allocate a single kmem_cache from the page allocator */
-       kmem_size = sizeof(struct kmem_cache);
-       order = get_order(kmem_size);
-       kmem_cache = (void *)__get_free_pages(GFP_NOWAIT, order);
-#endif
 
        /* Able to allocate the per node structures */
        slab_state = PARTIAL;
@@ -3063,7 +3039,6 @@ void __init kmem_cache_init(void)
        kmem_cache = kmem_cache_alloc(kmem_cache, GFP_NOWAIT);
        memcpy(kmem_cache, temp_kmem_cache, kmem_size);
 
-#ifdef CONFIG_NUMA
        /*
         * Allocate kmem_cache_node properly from the kmem_cache slab.
         * kmem_cache_node is separately allocated so no need to
@@ -3077,18 +3052,6 @@ void __init kmem_cache_init(void)
        kmem_cache_bootstrap_fixup(kmem_cache_node);
 
        caches++;
-#else
-       /*
-        * kmem_cache has kmem_cache_node embedded and we moved it!
-        * Update the list heads
-        */
-       INIT_LIST_HEAD(&kmem_cache->local_node.partial);
-       list_splice(&temp_kmem_cache->local_node.partial, &kmem_cache->local_node.partial);
-#ifdef CONFIG_SLUB_DEBUG
-       INIT_LIST_HEAD(&kmem_cache->local_node.full);
-       list_splice(&temp_kmem_cache->local_node.full, &kmem_cache->local_node.full);
-#endif
-#endif
        kmem_cache_bootstrap_fixup(kmem_cache);
        caches++;
        /* Free temporary boot structure */
@@ -3153,6 +3116,16 @@ void __init kmem_cache_init(void)
        slab_state = UP;
 
        /* Provide the correct kmalloc names now that the caches are up */
+       if (KMALLOC_MIN_SIZE <= 32) {
+               kmalloc_caches[1]->name = kstrdup(kmalloc_caches[1]->name, GFP_NOWAIT);
+               BUG_ON(!kmalloc_caches[1]->name);
+       }
+
+       if (KMALLOC_MIN_SIZE <= 64) {
+               kmalloc_caches[2]->name = kstrdup(kmalloc_caches[2]->name, GFP_NOWAIT);
+               BUG_ON(!kmalloc_caches[2]->name);
+       }
+
        for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
                char *s = kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);
 
@@ -3255,6 +3228,7 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                size_t align, unsigned long flags, void (*ctor)(void *))
 {
        struct kmem_cache *s;
+       char *n;
 
        if (WARN_ON(!name))
                return NULL;
@@ -3278,19 +3252,25 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                return s;
        }
 
+       n = kstrdup(name, GFP_KERNEL);
+       if (!n)
+               goto err;
+
        s = kmalloc(kmem_size, GFP_KERNEL);
        if (s) {
-               if (kmem_cache_open(s, name,
+               if (kmem_cache_open(s, n,
                                size, align, flags, ctor)) {
                        list_add(&s->list, &slab_caches);
                        if (sysfs_slab_add(s)) {
                                list_del(&s->list);
+                               kfree(n);
                                kfree(s);
                                goto err;
                        }
                        up_write(&slub_lock);
                        return s;
                }
+               kfree(n);
                kfree(s);
        }
        up_write(&slub_lock);
@@ -3498,6 +3478,8 @@ static void resiliency_test(void)
 {
        u8 *p;
 
+       BUILD_BUG_ON(KMALLOC_MIN_SIZE > 16 || SLUB_PAGE_SHIFT < 10);
+
        printk(KERN_ERR "SLUB resiliency testing\n");
        printk(KERN_ERR "-----------------------\n");
        printk(KERN_ERR "A. Corruption after allocation\n");
@@ -3507,7 +3489,7 @@ static void resiliency_test(void)
        printk(KERN_ERR "\n1. kmalloc-16: Clobber Redzone/next pointer"
                        " 0x12->0x%p\n\n", p + 16);
 
-       validate_slab_cache(kmalloc_caches + 4);
+       validate_slab_cache(kmalloc_caches[4]);
 
        /* Hmmm... The next two are dangerous */
        p = kzalloc(32, GFP_KERNEL);
@@ -3517,7 +3499,7 @@ static void resiliency_test(void)
        printk(KERN_ERR
                "If allocated object is overwritten then not detectable\n\n");
 
-       validate_slab_cache(kmalloc_caches + 5);
+       validate_slab_cache(kmalloc_caches[5]);
        p = kzalloc(64, GFP_KERNEL);
        p += 64 + (get_cycles() & 0xff) * sizeof(void *);
        *p = 0x56;
@@ -3525,27 +3507,27 @@ static void resiliency_test(void)
                                                                        p);
        printk(KERN_ERR
                "If allocated object is overwritten then not detectable\n\n");
-       validate_slab_cache(kmalloc_caches + 6);
+       validate_slab_cache(kmalloc_caches[6]);
 
        printk(KERN_ERR "\nB. Corruption after free\n");
        p = kzalloc(128, GFP_KERNEL);
        kfree(p);
        *p = 0x78;
        printk(KERN_ERR "1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p);
-       validate_slab_cache(kmalloc_caches + 7);
+       validate_slab_cache(kmalloc_caches[7]);
 
        p = kzalloc(256, GFP_KERNEL);
        kfree(p);
        p[50] = 0x9a;
        printk(KERN_ERR "\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n",
                        p);
-       validate_slab_cache(kmalloc_caches + 8);
+       validate_slab_cache(kmalloc_caches[8]);
 
        p = kzalloc(512, GFP_KERNEL);
        kfree(p);
        p[512] = 0xab;
        printk(KERN_ERR "\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p);
-       validate_slab_cache(kmalloc_caches + 9);
+       validate_slab_cache(kmalloc_caches[9]);
 }
 #else
 static void resiliency_test(void) {};
@@ -3679,7 +3661,7 @@ static int add_location(struct loc_track *t, struct kmem_cache *s,
 
 static void process_slab(struct loc_track *t, struct kmem_cache *s,
                struct page *page, enum track_item alloc,
-               long *map)
+               unsigned long *map)
 {
        void *addr = page_address(page);
        void *p;
@@ -4421,6 +4403,7 @@ static void kmem_cache_release(struct kobject *kobj)
 {
        struct kmem_cache *s = to_slab(kobj);
 
+       kfree(s->name);
        kfree(s);
 }