]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
mm, slub: do initial checks in ___slab_alloc() with irqs enabled
authorVlastimil Babka <vbabka@suse.cz>
Mon, 23 Aug 2021 23:58:56 +0000 (09:58 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Wed, 25 Aug 2021 23:33:27 +0000 (09:33 +1000)
As another step of shortening irq disabled sections in ___slab_alloc(),
delay disabling irqs until we pass the initial checks if there is a cached
percpu slab and it's suitable for our allocation.

Now we have to recheck c->page after actually disabling irqs as an
allocation in irq handler might have replaced it.

Because we call pfmemalloc_match() as one of the checks, we might hit
VM_BUG_ON_PAGE(!PageSlab(page)) in PageSlabPfmemalloc in case we get
interrupted and the page is freed.  Thus introduce a
pfmemalloc_match_unsafe() variant that lacks the PageSlab check.

Link: https://lkml.kernel.org/r/20210805152000.12817-14-vbabka@suse.cz
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
Acked-by: Mel Gorman <mgorman@techsingularity.net>
Cc: Christoph Lameter <cl@linux.com>
Cc: David Rientjes <rientjes@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Jesper Dangaard Brouer <brouer@redhat.com>
Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
mm/slub.c

index 31f946e038232412bd4375f3f6e83cebf6d77446..d1d39135d9f9999d14c6e6831a2764dc3aededc6 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -2668,8 +2668,9 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
 
        stat(s, ALLOC_SLOWPATH);
 
-       local_irq_save(flags);
-       page = c->page;
+reread_page:
+
+       page = READ_ONCE(c->page);
        if (!page) {
                /*
                 * if the node is not online or has no normal memory, just
@@ -2678,6 +2679,11 @@ static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
                if (unlikely(node != NUMA_NO_NODE &&
                             !node_isset(node, slab_nodes)))
                        node = NUMA_NO_NODE;
+               local_irq_save(flags);
+               if (unlikely(c->page)) {
+                       local_irq_restore(flags);
+                       goto reread_page;
+               }
                goto new_slab;
        }
 redo:
@@ -2692,8 +2698,7 @@ redo:
                        goto redo;
                } else {
                        stat(s, ALLOC_NODE_MISMATCH);
-                       deactivate_slab(s, page, c->freelist, c);
-                       goto new_slab;
+                       goto deactivate_slab;
                }
        }
 
@@ -2702,12 +2707,15 @@ redo:
         * PFMEMALLOC but right now, we are losing the pfmemalloc
         * information when the page leaves the per-cpu allocator
         */
-       if (unlikely(!pfmemalloc_match(page, gfpflags))) {
-               deactivate_slab(s, page, c->freelist, c);
-               goto new_slab;
-       }
+       if (unlikely(!pfmemalloc_match(page, gfpflags)))
+               goto deactivate_slab;
 
-       /* must check again c->freelist in case of cpu migration or IRQ */
+       /* must check again c->page in case IRQ handler changed it */
+       local_irq_save(flags);
+       if (unlikely(page != c->page)) {
+               local_irq_restore(flags);
+               goto reread_page;
+       }
        freelist = c->freelist;
        if (freelist)
                goto load_freelist;
@@ -2723,6 +2731,9 @@ redo:
        stat(s, ALLOC_REFILL);
 
 load_freelist:
+
+       lockdep_assert_irqs_disabled();
+
        /*
         * freelist is pointing to the list of objects to be used.
         * page is pointing to the page from which the objects are obtained.
@@ -2734,11 +2745,23 @@ load_freelist:
        local_irq_restore(flags);
        return freelist;
 
+deactivate_slab:
+
+       local_irq_save(flags);
+       if (page != c->page) {
+               local_irq_restore(flags);
+               goto reread_page;
+       }
+       deactivate_slab(s, page, c->freelist, c);
+
 new_slab:
 
+       lockdep_assert_irqs_disabled();
+
        if (slub_percpu_partial(c)) {
                page = c->page = slub_percpu_partial(c);
                slub_set_percpu_partial(c, page);
+               local_irq_restore(flags);
                stat(s, CPU_PARTIAL_ALLOC);
                goto redo;
        }