mm, slub: extract get_partial() from new_slab_objects()
[linux-2.6-microblaze.git] / mm / slub.c
index f77d8cd..cd6aeee 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -454,6 +454,18 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
 static unsigned long object_map[BITS_TO_LONGS(MAX_OBJS_PER_PAGE)];
 static DEFINE_SPINLOCK(object_map_lock);
 
+static void __fill_map(unsigned long *obj_map, struct kmem_cache *s,
+                      struct page *page)
+{
+       void *addr = page_address(page);
+       void *p;
+
+       bitmap_zero(obj_map, page->objects);
+
+       for (p = page->freelist; p; p = get_freepointer(s, p))
+               set_bit(__obj_to_index(s, addr, p), obj_map);
+}
+
 #if IS_ENABLED(CONFIG_KUNIT)
 static bool slab_add_kunit_errors(void)
 {
@@ -483,17 +495,11 @@ static inline bool slab_add_kunit_errors(void) { return false; }
 static unsigned long *get_map(struct kmem_cache *s, struct page *page)
        __acquires(&object_map_lock)
 {
-       void *p;
-       void *addr = page_address(page);
-
        VM_BUG_ON(!irqs_disabled());
 
        spin_lock(&object_map_lock);
 
-       bitmap_zero(object_map, page->objects);
-
-       for (p = page->freelist; p; p = get_freepointer(s, p))
-               set_bit(__obj_to_index(s, addr, p), object_map);
+       __fill_map(object_map, s, page);
 
        return object_map;
 }
@@ -1585,20 +1591,8 @@ static __always_inline bool slab_free_hook(struct kmem_cache *s,
 {
        kmemleak_free_recursive(x, s->flags);
 
-       /*
-        * Trouble is that we may no longer disable interrupts in the fast path
-        * So in order to make the debug calls that expect irqs to be
-        * disabled we need to disable interrupts temporarily.
-        */
-#ifdef CONFIG_LOCKDEP
-       {
-               unsigned long flags;
+       debug_check_no_locks_freed(x, s->object_size);
 
-               local_irq_save(flags);
-               debug_check_no_locks_freed(x, s->object_size);
-               local_irq_restore(flags);
-       }
-#endif
        if (!(s->flags & SLAB_DEBUG_OBJECTS))
                debug_check_no_obj_freed(x, s->object_size);
 
@@ -2472,13 +2466,6 @@ static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain)
 
        } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page)
                                                                != oldpage);
-       if (unlikely(!slub_cpu_partial(s))) {
-               unsigned long flags;
-
-               local_irq_save(flags);
-               unfreeze_partials(s, this_cpu_ptr(s->cpu_slab));
-               local_irq_restore(flags);
-       }
        preempt_enable();
 #endif /* CONFIG_SLUB_CPU_PARTIAL */
 }
@@ -2626,17 +2613,12 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid)
 static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
                        int node, struct kmem_cache_cpu **pc)
 {
-       void *freelist;
+       void *freelist = NULL;
        struct kmem_cache_cpu *c = *pc;
        struct page *page;
 
        WARN_ON_ONCE(s->ctor && (flags & __GFP_ZERO));
 
-       freelist = get_partial(s, flags, node, c);
-
-       if (freelist)
-               return freelist;
-
        page = new_slab(s, flags, node);
        if (page) {
                c = raw_cpu_ptr(s->cpu_slab);
@@ -2800,6 +2782,10 @@ new_slab:
                goto redo;
        }
 
+       freelist = get_partial(s, gfpflags, node, c);
+       if (freelist)
+               goto check_new_page;
+
        freelist = new_slab_objects(s, gfpflags, node, &c);
 
        if (unlikely(!freelist)) {
@@ -2807,6 +2793,7 @@ new_slab:
                return NULL;
        }
 
+check_new_page:
        page = c->page;
        if (likely(!kmem_cache_debug(s) && pfmemalloc_match(page, gfpflags)))
                goto load_freelist;
@@ -4673,11 +4660,11 @@ static int count_total(struct page *page)
 #endif
 
 #ifdef CONFIG_SLUB_DEBUG
-static void validate_slab(struct kmem_cache *s, struct page *page)
+static void validate_slab(struct kmem_cache *s, struct page *page,
+                         unsigned long *obj_map)
 {
        void *p;
        void *addr = page_address(page);
-       unsigned long *map;
 
        slab_lock(page);
 
@@ -4685,21 +4672,20 @@ static void validate_slab(struct kmem_cache *s, struct page *page)
                goto unlock;
 
        /* Now we know that a valid freelist exists */
-       map = get_map(s, page);
+       __fill_map(obj_map, s, page);
        for_each_object(p, s, addr, page->objects) {
-               u8 val = test_bit(__obj_to_index(s, addr, p), map) ?
+               u8 val = test_bit(__obj_to_index(s, addr, p), obj_map) ?
                         SLUB_RED_INACTIVE : SLUB_RED_ACTIVE;
 
                if (!check_object(s, page, p, val))
                        break;
        }
-       put_map(map);
 unlock:
        slab_unlock(page);
 }
 
 static int validate_slab_node(struct kmem_cache *s,
-               struct kmem_cache_node *n)
+               struct kmem_cache_node *n, unsigned long *obj_map)
 {
        unsigned long count = 0;
        struct page *page;
@@ -4708,7 +4694,7 @@ static int validate_slab_node(struct kmem_cache *s,
        spin_lock_irqsave(&n->list_lock, flags);
 
        list_for_each_entry(page, &n->partial, slab_list) {
-               validate_slab(s, page);
+               validate_slab(s, page, obj_map);
                count++;
        }
        if (count != n->nr_partial) {
@@ -4721,7 +4707,7 @@ static int validate_slab_node(struct kmem_cache *s,
                goto out;
 
        list_for_each_entry(page, &n->full, slab_list) {
-               validate_slab(s, page);
+               validate_slab(s, page, obj_map);
                count++;
        }
        if (count != atomic_long_read(&n->nr_slabs)) {
@@ -4740,10 +4726,17 @@ long validate_slab_cache(struct kmem_cache *s)
        int node;
        unsigned long count = 0;
        struct kmem_cache_node *n;
+       unsigned long *obj_map;
+
+       obj_map = bitmap_alloc(oo_objects(s->oo), GFP_KERNEL);
+       if (!obj_map)
+               return -ENOMEM;
 
        flush_all(s);
        for_each_kmem_cache_node(s, node, n)
-               count += validate_slab_node(s, n);
+               count += validate_slab_node(s, n, obj_map);
+
+       bitmap_free(obj_map);
 
        return count;
 }
@@ -4879,17 +4872,17 @@ 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)
+               struct page *page, enum track_item alloc,
+               unsigned long *obj_map)
 {
        void *addr = page_address(page);
        void *p;
-       unsigned long *map;
 
-       map = get_map(s, page);
+       __fill_map(obj_map, s, page);
+
        for_each_object(p, s, addr, page->objects)
-               if (!test_bit(__obj_to_index(s, addr, p), map))
+               if (!test_bit(__obj_to_index(s, addr, p), obj_map))
                        add_location(t, s, get_track(s, p, alloc));
-       put_map(map);
 }
 #endif  /* CONFIG_DEBUG_FS   */
 #endif /* CONFIG_SLUB_DEBUG */
@@ -5816,17 +5809,21 @@ static int slab_debug_trace_open(struct inode *inode, struct file *filep)
        struct loc_track *t = __seq_open_private(filep, &slab_debugfs_sops,
                                                sizeof(struct loc_track));
        struct kmem_cache *s = file_inode(filep)->i_private;
+       unsigned long *obj_map;
+
+       obj_map = bitmap_alloc(oo_objects(s->oo), GFP_KERNEL);
+       if (!obj_map)
+               return -ENOMEM;
 
        if (strcmp(filep->f_path.dentry->d_name.name, "alloc_traces") == 0)
                alloc = TRACK_ALLOC;
        else
                alloc = TRACK_FREE;
 
-       if (!alloc_loc_track(t, PAGE_SIZE / sizeof(struct location), GFP_KERNEL))
+       if (!alloc_loc_track(t, PAGE_SIZE / sizeof(struct location), GFP_KERNEL)) {
+               bitmap_free(obj_map);
                return -ENOMEM;
-
-       /* Push back cpu slabs */
-       flush_all(s);
+       }
 
        for_each_kmem_cache_node(s, node, n) {
                unsigned long flags;
@@ -5837,12 +5834,13 @@ static int slab_debug_trace_open(struct inode *inode, struct file *filep)
 
                spin_lock_irqsave(&n->list_lock, flags);
                list_for_each_entry(page, &n->partial, slab_list)
-                       process_slab(t, s, page, alloc);
+                       process_slab(t, s, page, alloc, obj_map);
                list_for_each_entry(page, &n->full, slab_list)
-                       process_slab(t, s, page, alloc);
+                       process_slab(t, s, page, alloc, obj_map);
                spin_unlock_irqrestore(&n->list_lock, flags);
        }
 
+       bitmap_free(obj_map);
        return 0;
 }