Merge branch 'slub/cleanups' into slab/next
authorPekka Enberg <penberg@kernel.org>
Mon, 4 Jun 2012 07:14:58 +0000 (10:14 +0300)
committerPekka Enberg <penberg@kernel.org>
Mon, 4 Jun 2012 07:14:58 +0000 (10:14 +0300)
* Fix a merge conflict in mm/slub.c::acquire_slab() due to commit 02d7633
  ("slub: fix a memory leak in get_partial_node()").

Conflicts:
mm/slub.c

Signed-off-by: Pekka Enberg <penberg@kernel.org>
1  2 
mm/slub.c

diff --combined mm/slub.c
index 8c691fa1cf3c78a91fa301bcd0cd323df1b28a1e,719509eaa46774fcc132644f6a0b0c1da70f2773..2de3c996f327079bdae3de9262bf69ba2bab496e
+++ b/mm/slub.c
@@@ -1369,7 -1369,7 +1369,7 @@@ static struct page *new_slab(struct kme
  
        inc_slabs_node(s, page_to_nid(page), page->objects);
        page->slab = s;
 -      page->flags |= 1 << PG_slab;
 +      __SetPageSlab(page);
  
        start = page_address(page);
  
@@@ -1490,12 -1490,12 +1490,12 @@@ static inline void remove_partial(struc
  }
  
  /*
-  * Lock slab, remove from the partial list and put the object into the
-  * per cpu freelist.
+  * Remove slab from the partial list, freeze it and
+  * return the pointer to the freelist.
   *
   * Returns a list of objects or NULL if it fails.
   *
-  * Must hold list_lock.
+  * Must hold list_lock since we modify the partial list.
   */
  static inline void *acquire_slab(struct kmem_cache *s,
                struct kmem_cache_node *n, struct page *page,
         * The old freelist is the list of objects for the
         * per cpu allocation list.
         */
-       do {
-               freelist = page->freelist;
-               counters = page->counters;
-               new.counters = counters;
-               if (mode) {
-                       new.inuse = page->objects;
-                       new.freelist = NULL;
-               } else {
-                       new.freelist = freelist;
-               }
+       freelist = page->freelist;
+       counters = page->counters;
+       new.counters = counters;
 -      if (mode)
++      if (mode) {
+               new.inuse = page->objects;
++              new.freelist = NULL;
++      } else {
++              new.freelist = freelist;
++      }
  
-               VM_BUG_ON(new.frozen);
-               new.frozen = 1;
+       VM_BUG_ON(new.frozen);
+       new.frozen = 1;
  
-       } while (!__cmpxchg_double_slab(s, page,
+       if (!__cmpxchg_double_slab(s, page,
                        freelist, counters,
 -                      NULL, new.counters,
 +                      new.freelist, new.counters,
-                       "lock and freeze"));
+                       "acquire_slab"))
 -
+               return NULL;
  
        remove_partial(n, page);
+       WARN_ON(!freelist);
        return freelist;
  }
  
@@@ -1563,11 -1561,11 +1564,10 @@@ static void *get_partial_node(struct km
  
                if (!object) {
                        c->page = page;
-                       c->node = page_to_nid(page);
                        stat(s, ALLOC_FROM_PARTIAL);
                        object = t;
                        available =  page->objects - page->inuse;
                } else {
 -                      page->freelist = t;
                        available = put_cpu_partial(s, page, 0);
                        stat(s, CPU_PARTIAL_NODE);
                }
  /*
   * Get a page from somewhere. Search in increasing NUMA distances.
   */
 -static struct page *get_any_partial(struct kmem_cache *s, gfp_t flags,
 +static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
                struct kmem_cache_cpu *c)
  {
  #ifdef CONFIG_NUMA
@@@ -1731,14 -1729,12 +1731,12 @@@ void init_kmem_cache_cpus(struct kmem_c
  /*
   * Remove the cpu slab
   */
- static void deactivate_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
+ static void deactivate_slab(struct kmem_cache *s, struct page *page, void *freelist)
  {
        enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
-       struct page *page = c->page;
        struct kmem_cache_node *n = get_node(s, page_to_nid(page));
        int lock = 0;
        enum slab_modes l = M_NONE, m = M_NONE;
-       void *freelist;
        void *nextfree;
        int tail = DEACTIVATE_TO_HEAD;
        struct page new;
                tail = DEACTIVATE_TO_TAIL;
        }
  
-       c->tid = next_tid(c->tid);
-       c->page = NULL;
-       freelist = c->freelist;
-       c->freelist = NULL;
        /*
         * Stage one: Free all available per cpu objects back
         * to the page freelist while it is still frozen. Leave the
@@@ -2011,7 -2002,11 +2004,11 @@@ int put_cpu_partial(struct kmem_cache *
  static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
  {
        stat(s, CPUSLAB_FLUSH);
-       deactivate_slab(s, c);
+       deactivate_slab(s, c->page, c->freelist);
+       c->tid = next_tid(c->tid);
+       c->page = NULL;
+       c->freelist = NULL;
  }
  
  /*
@@@ -2055,10 -2050,10 +2052,10 @@@ static void flush_all(struct kmem_cach
   * Check if the objects in a per cpu structure fit numa
   * locality expectations.
   */
- static inline int node_match(struct kmem_cache_cpu *c, int node)
+ static inline int node_match(struct page *page, int node)
  {
  #ifdef CONFIG_NUMA
-       if (node != NUMA_NO_NODE && c->node != node)
+       if (node != NUMA_NO_NODE && page_to_nid(page) != node)
                return 0;
  #endif
        return 1;
@@@ -2130,10 -2125,16 +2127,16 @@@ slab_out_of_memory(struct kmem_cache *s
  static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
                        int node, struct kmem_cache_cpu **pc)
  {
-       void *object;
-       struct kmem_cache_cpu *c;
-       struct page *page = new_slab(s, flags, node);
+       void *freelist;
+       struct kmem_cache_cpu *c = *pc;
+       struct page *page;
  
+       freelist = get_partial(s, flags, node, c);
+       if (freelist)
+               return freelist;
+       page = new_slab(s, flags, node);
        if (page) {
                c = __this_cpu_ptr(s->cpu_slab);
                if (c->page)
                 * No other reference to the page yet so we can
                 * muck around with it freely without cmpxchg
                 */
-               object = page->freelist;
+               freelist = page->freelist;
                page->freelist = NULL;
  
                stat(s, ALLOC_SLAB);
-               c->node = page_to_nid(page);
                c->page = page;
                *pc = c;
        } else
-               object = NULL;
+               freelist = NULL;
  
-       return object;
+       return freelist;
  }
  
  /*
@@@ -2173,6 -2173,7 +2175,7 @@@ static inline void *get_freelist(struc
        do {
                freelist = page->freelist;
                counters = page->counters;
                new.counters = counters;
                VM_BUG_ON(!new.frozen);
  
  static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
                          unsigned long addr, struct kmem_cache_cpu *c)
  {
-       void **object;
+       void *freelist;
+       struct page *page;
        unsigned long flags;
  
        local_irq_save(flags);
        c = this_cpu_ptr(s->cpu_slab);
  #endif
  
-       if (!c->page)
+       page = c->page;
+       if (!page)
                goto new_slab;
  redo:
-       if (unlikely(!node_match(c, node))) {
+       if (unlikely(!node_match(page, node))) {
                stat(s, ALLOC_NODE_MISMATCH);
-               deactivate_slab(s, c);
+               deactivate_slab(s, page, c->freelist);
+               c->page = NULL;
+               c->freelist = NULL;
                goto new_slab;
        }
  
        /* must check again c->freelist in case of cpu migration or IRQ */
-       object = c->freelist;
-       if (object)
+       freelist = c->freelist;
+       if (freelist)
                goto load_freelist;
  
        stat(s, ALLOC_SLOWPATH);
  
-       object = get_freelist(s, c->page);
+       freelist = get_freelist(s, page);
  
-       if (!object) {
+       if (!freelist) {
                c->page = NULL;
                stat(s, DEACTIVATE_BYPASS);
                goto new_slab;
        stat(s, ALLOC_REFILL);
  
  load_freelist:
-       c->freelist = get_freepointer(s, object);
+       /*
+        * freelist is pointing to the list of objects to be used.
+        * page is pointing to the page from which the objects are obtained.
+        * That page must be frozen for per cpu allocations to work.
+        */
+       VM_BUG_ON(!c->page->frozen);
+       c->freelist = get_freepointer(s, freelist);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
-       return object;
+       return freelist;
  
  new_slab:
  
        if (c->partial) {
-               c->page = c->partial;
-               c->partial = c->page->next;
-               c->node = page_to_nid(c->page);
+               page = c->page = c->partial;
+               c->partial = page->next;
                stat(s, CPU_PARTIAL_ALLOC);
                c->freelist = NULL;
                goto redo;
        }
  
-       /* Then do expensive stuff like retrieving pages from the partial lists */
-       object = get_partial(s, gfpflags, node, c);
-       if (unlikely(!object)) {
+       freelist = new_slab_objects(s, gfpflags, node, &c);
  
-               object = new_slab_objects(s, gfpflags, node, &c);
+       if (unlikely(!freelist)) {
+               if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
+                       slab_out_of_memory(s, gfpflags, node);
  
-               if (unlikely(!object)) {
-                       if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
-                               slab_out_of_memory(s, gfpflags, node);
-                       local_irq_restore(flags);
-                       return NULL;
-               }
+               local_irq_restore(flags);
+               return NULL;
        }
  
+       page = c->page;
        if (likely(!kmem_cache_debug(s)))
                goto load_freelist;
  
        /* Only entered in the debug case */
-       if (!alloc_debug_processing(s, c->page, object, addr))
+       if (!alloc_debug_processing(s, page, freelist, addr))
                goto new_slab;  /* Slab failed checks. Next slab needed */
  
-       c->freelist = get_freepointer(s, object);
-       deactivate_slab(s, c);
-       c->node = NUMA_NO_NODE;
+       deactivate_slab(s, page, get_freepointer(s, freelist));
+       c->page = NULL;
+       c->freelist = NULL;
        local_irq_restore(flags);
-       return object;
+       return freelist;
  }
  
  /*
@@@ -2307,6 -2313,7 +2315,7 @@@ static __always_inline void *slab_alloc
  {
        void **object;
        struct kmem_cache_cpu *c;
+       struct page *page;
        unsigned long tid;
  
        if (slab_pre_alloc_hook(s, gfpflags))
@@@ -2332,7 -2339,8 +2341,8 @@@ redo
        barrier();
  
        object = c->freelist;
-       if (unlikely(!object || !node_match(c, node)))
+       page = c->page;
+       if (unlikely(!object || !node_match(page, node)))
  
                object = __slab_alloc(s, gfpflags, node, addr, c);
  
@@@ -2769,7 -2777,7 +2779,7 @@@ static unsigned long calculate_alignmen
  }
  
  static void
 -init_kmem_cache_node(struct kmem_cache_node *n, struct kmem_cache *s)
 +init_kmem_cache_node(struct kmem_cache_node *n)
  {
        n->nr_partial = 0;
        spin_lock_init(&n->list_lock);
@@@ -2839,7 -2847,7 +2849,7 @@@ static void early_kmem_cache_node_alloc
        init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
        init_tracking(kmem_cache_node, n);
  #endif
 -      init_kmem_cache_node(n, kmem_cache_node);
 +      init_kmem_cache_node(n);
        inc_slabs_node(kmem_cache_node, node, page->objects);
  
        add_partial(n, page, DEACTIVATE_TO_HEAD);
@@@ -2879,7 -2887,7 +2889,7 @@@ static int init_kmem_cache_nodes(struc
                }
  
                s->node[node] = n;
 -              init_kmem_cache_node(n, s);
 +              init_kmem_cache_node(n);
        }
        return 1;
  }
@@@ -3628,7 -3636,7 +3638,7 @@@ static int slab_mem_going_online_callba
                        ret = -ENOMEM;
                        goto out;
                }
 -              init_kmem_cache_node(n, s);
 +              init_kmem_cache_node(n);
                s->node[nid] = n;
        }
  out:
@@@ -3971,9 -3979,9 +3981,9 @@@ struct kmem_cache *kmem_cache_create(co
                        }
                        return s;
                }
 -              kfree(n);
                kfree(s);
        }
 +      kfree(n);
  err:
        up_write(&slub_lock);
  
@@@ -4500,30 -4508,31 +4510,31 @@@ static ssize_t show_slab_objects(struc
  
                for_each_possible_cpu(cpu) {
                        struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
-                       int node = ACCESS_ONCE(c->node);
+                       int node;
                        struct page *page;
  
-                       if (node < 0)
-                               continue;
                        page = ACCESS_ONCE(c->page);
-                       if (page) {
-                               if (flags & SO_TOTAL)
-                                       x = page->objects;
-                               else if (flags & SO_OBJECTS)
-                                       x = page->inuse;
-                               else
-                                       x = 1;
+                       if (!page)
+                               continue;
  
-                               total += x;
-                               nodes[node] += x;
-                       }
-                       page = c->partial;
+                       node = page_to_nid(page);
+                       if (flags & SO_TOTAL)
+                               x = page->objects;
+                       else if (flags & SO_OBJECTS)
+                               x = page->inuse;
+                       else
+                               x = 1;
  
+                       total += x;
+                       nodes[node] += x;
+                       page = ACCESS_ONCE(c->partial);
                        if (page) {
                                x = page->pobjects;
                                total += x;
                                nodes[node] += x;
                        }
                        per_cpu[node]++;
                }
        }