]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - mm/slub.c
PCI: Expand Enhanced Allocation BAR output
[karo-tx-linux.git] / mm / slub.c
index f68c0e50f3c083abe295a1dcd60668321a8f9232..f614b5dc396bc17b43cebacd97383243bbb03b99 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1306,6 +1306,17 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
        kasan_slab_free(s, x);
 }
 
+static void setup_object(struct kmem_cache *s, struct page *page,
+                               void *object)
+{
+       setup_object_debug(s, page, object);
+       if (unlikely(s->ctor)) {
+               kasan_unpoison_object_data(s, object);
+               s->ctor(object);
+               kasan_poison_object_data(s, object);
+       }
+}
+
 /*
  * Slab allocation and freeing
  */
@@ -1323,7 +1334,7 @@ static inline struct page *alloc_slab_page(struct kmem_cache *s,
        if (node == NUMA_NO_NODE)
                page = alloc_pages(flags, order);
        else
-               page = alloc_pages_exact_node(node, flags, order);
+               page = __alloc_pages_node(node, flags, order);
 
        if (!page)
                memcg_uncharge_slab(s, order);
@@ -1336,6 +1347,8 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
        struct page *page;
        struct kmem_cache_order_objects oo = s->oo;
        gfp_t alloc_gfp;
+       void *start, *p;
+       int idx, order;
 
        flags &= gfp_allowed_mask;
 
@@ -1349,6 +1362,8 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
         * so we fall-back to the minimum order allocation.
         */
        alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL;
+       if ((alloc_gfp & __GFP_WAIT) && oo_order(oo) > oo_order(s->min))
+               alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~__GFP_WAIT;
 
        page = alloc_slab_page(s, alloc_gfp, node, oo);
        if (unlikely(!page)) {
@@ -1359,13 +1374,13 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
                 * Try a lower order alloc if possible
                 */
                page = alloc_slab_page(s, alloc_gfp, node, oo);
-
-               if (page)
-                       stat(s, ORDER_FALLBACK);
+               if (unlikely(!page))
+                       goto out;
+               stat(s, ORDER_FALLBACK);
        }
 
-       if (kmemcheck_enabled && page
-               && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
+       if (kmemcheck_enabled &&
+           !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
                int pages = 1 << oo_order(oo);
 
                kmemcheck_alloc_shadow(page, oo_order(oo), alloc_gfp, node);
@@ -1380,51 +1395,9 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
                        kmemcheck_mark_unallocated_pages(page, pages);
        }
 
-       if (flags & __GFP_WAIT)
-               local_irq_disable();
-       if (!page)
-               return NULL;
-
        page->objects = oo_objects(oo);
-       mod_zone_page_state(page_zone(page),
-               (s->flags & SLAB_RECLAIM_ACCOUNT) ?
-               NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
-               1 << oo_order(oo));
-
-       return page;
-}
-
-static void setup_object(struct kmem_cache *s, struct page *page,
-                               void *object)
-{
-       setup_object_debug(s, page, object);
-       if (unlikely(s->ctor)) {
-               kasan_unpoison_object_data(s, object);
-               s->ctor(object);
-               kasan_poison_object_data(s, object);
-       }
-}
-
-static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
-{
-       struct page *page;
-       void *start;
-       void *p;
-       int order;
-       int idx;
-
-       if (unlikely(flags & GFP_SLAB_BUG_MASK)) {
-               pr_emerg("gfp: %u\n", flags & GFP_SLAB_BUG_MASK);
-               BUG();
-       }
-
-       page = allocate_slab(s,
-               flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
-       if (!page)
-               goto out;
 
        order = compound_order(page);
-       inc_slabs_node(s, page_to_nid(page), page->objects);
        page->slab_cache = s;
        __SetPageSlab(page);
        if (page_is_pfmemalloc(page))
@@ -1448,10 +1421,34 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
        page->freelist = start;
        page->inuse = page->objects;
        page->frozen = 1;
+
 out:
+       if (flags & __GFP_WAIT)
+               local_irq_disable();
+       if (!page)
+               return NULL;
+
+       mod_zone_page_state(page_zone(page),
+               (s->flags & SLAB_RECLAIM_ACCOUNT) ?
+               NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
+               1 << oo_order(oo));
+
+       inc_slabs_node(s, page_to_nid(page), page->objects);
+
        return page;
 }
 
+static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
+{
+       if (unlikely(flags & GFP_SLAB_BUG_MASK)) {
+               pr_emerg("gfp: %u\n", flags & GFP_SLAB_BUG_MASK);
+               BUG();
+       }
+
+       return allocate_slab(s,
+               flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
+}
+
 static void __free_slab(struct kmem_cache *s, struct page *page)
 {
        int order = compound_order(page);
@@ -2712,7 +2709,7 @@ redo:
         * Determine the currently cpus per cpu slab.
         * The cpu may change afterward. However that does not matter since
         * data is retrieved via this pointer. If we are on the same cpu
-        * during the cmpxchg then the free will succedd.
+        * during the cmpxchg then the free will succeed.
         */
        do {
                tid = this_cpu_read(s->cpu_slab->tid);
@@ -2750,6 +2747,113 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
 }
 EXPORT_SYMBOL(kmem_cache_free);
 
+/* Note that interrupts must be enabled when calling this function. */
+void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
+{
+       struct kmem_cache_cpu *c;
+       struct page *page;
+       int i;
+
+       local_irq_disable();
+       c = this_cpu_ptr(s->cpu_slab);
+
+       for (i = 0; i < size; i++) {
+               void *object = p[i];
+
+               BUG_ON(!object);
+               /* kmem cache debug support */
+               s = cache_from_obj(s, object);
+               if (unlikely(!s))
+                       goto exit;
+               slab_free_hook(s, object);
+
+               page = virt_to_head_page(object);
+
+               if (c->page == page) {
+                       /* Fastpath: local CPU free */
+                       set_freepointer(s, object, c->freelist);
+                       c->freelist = object;
+               } else {
+                       c->tid = next_tid(c->tid);
+                       local_irq_enable();
+                       /* Slowpath: overhead locked cmpxchg_double_slab */
+                       __slab_free(s, page, object, _RET_IP_);
+                       local_irq_disable();
+                       c = this_cpu_ptr(s->cpu_slab);
+               }
+       }
+exit:
+       c->tid = next_tid(c->tid);
+       local_irq_enable();
+}
+EXPORT_SYMBOL(kmem_cache_free_bulk);
+
+/* Note that interrupts must be enabled when calling this function. */
+bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+                          void **p)
+{
+       struct kmem_cache_cpu *c;
+       int i;
+
+       /*
+        * Drain objects in the per cpu slab, while disabling local
+        * IRQs, which protects against PREEMPT and interrupts
+        * handlers invoking normal fastpath.
+        */
+       local_irq_disable();
+       c = this_cpu_ptr(s->cpu_slab);
+
+       for (i = 0; i < size; i++) {
+               void *object = c->freelist;
+
+               if (unlikely(!object)) {
+                       local_irq_enable();
+                       /*
+                        * Invoking slow path likely have side-effect
+                        * of re-populating per CPU c->freelist
+                        */
+                       p[i] = __slab_alloc(s, flags, NUMA_NO_NODE,
+                                           _RET_IP_, c);
+                       if (unlikely(!p[i])) {
+                               __kmem_cache_free_bulk(s, i, p);
+                               return false;
+                       }
+                       local_irq_disable();
+                       c = this_cpu_ptr(s->cpu_slab);
+                       continue; /* goto for-loop */
+               }
+
+               /* kmem_cache debug support */
+               s = slab_pre_alloc_hook(s, flags);
+               if (unlikely(!s)) {
+                       __kmem_cache_free_bulk(s, i, p);
+                       c->tid = next_tid(c->tid);
+                       local_irq_enable();
+                       return false;
+               }
+
+               c->freelist = get_freepointer(s, object);
+               p[i] = object;
+
+               /* kmem_cache debug support */
+               slab_post_alloc_hook(s, flags, object);
+       }
+       c->tid = next_tid(c->tid);
+       local_irq_enable();
+
+       /* Clear memory outside IRQ disabled fastpath loop */
+       if (unlikely(flags & __GFP_ZERO)) {
+               int j;
+
+               for (j = 0; j < i; j++)
+                       memset(p[j], 0, s->object_size);
+       }
+
+       return true;
+}
+EXPORT_SYMBOL(kmem_cache_alloc_bulk);
+
+
 /*
  * Object placement in a slab is made very easy because we always start at
  * offset 0. If we tune the size of the object to the alignment then we can
@@ -5181,7 +5285,7 @@ static int sysfs_slab_add(struct kmem_cache *s)
        s->kobj.kset = cache_kset(s);
        err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, "%s", name);
        if (err)
-               goto out_put_kobj;
+               goto out;
 
        err = sysfs_create_group(&s->kobj, &slab_attr_group);
        if (err)
@@ -5208,8 +5312,6 @@ out:
        return err;
 out_del_kobj:
        kobject_del(&s->kobj);
-out_put_kobj:
-       kobject_put(&s->kobj);
        goto out;
 }