summaryrefslogtreecommitdiff
path: root/patches/mm__slub__Move_flush_cpu_slab_invocations___free_slab_invocations_out_of_IRQ_context.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/mm__slub__Move_flush_cpu_slab_invocations___free_slab_invocations_out_of_IRQ_context.patch')
-rw-r--r--patches/mm__slub__Move_flush_cpu_slab_invocations___free_slab_invocations_out_of_IRQ_context.patch109
1 files changed, 109 insertions, 0 deletions
diff --git a/patches/mm__slub__Move_flush_cpu_slab_invocations___free_slab_invocations_out_of_IRQ_context.patch b/patches/mm__slub__Move_flush_cpu_slab_invocations___free_slab_invocations_out_of_IRQ_context.patch
new file mode 100644
index 000000000000..cc6a0eaa99b5
--- /dev/null
+++ b/patches/mm__slub__Move_flush_cpu_slab_invocations___free_slab_invocations_out_of_IRQ_context.patch
@@ -0,0 +1,109 @@
+Subject: mm: slub: Move flush_cpu_slab() invocations __free_slab() invocations out of IRQ context
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Date: Fri Feb 26 17:11:55 2021 +0100
+
+From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+
+flush_all() flushes a specific SLAB cache on each CPU (where the cache
+is present). The deactivate_slab()/__free_slab() invocation happens
+within IPI handler and is problematic for PREEMPT_RT.
+
+The flush operation is not a frequent operation or a hot path. The
+per-CPU flush operation can be moved to within a workqueue.
+
+[vbabka@suse.cz: adapt to new SLUB changes]
+Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
+Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
+
+
+---
+ mm/slub.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++--------
+ 1 file changed, 48 insertions(+), 8 deletions(-)
+---
+diff --git a/mm/slub.c b/mm/slub.c
+index 60ee128f8004..01defffad919 100644
+--- a/mm/slub.c
++++ b/mm/slub.c
+@@ -2475,33 +2475,73 @@ static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
+ unfreeze_partials_cpu(s, c);
+ }
+
++struct slub_flush_work {
++ struct work_struct work;
++ struct kmem_cache *s;
++ bool skip;
++};
++
+ /*
+ * Flush cpu slab.
+ *
+- * Called from IPI handler with interrupts disabled.
++ * Called from CPU work handler with migration disabled.
+ */
+-static void flush_cpu_slab(void *d)
++static void flush_cpu_slab(struct work_struct *w)
+ {
+- struct kmem_cache *s = d;
+- struct kmem_cache_cpu *c = this_cpu_ptr(s->cpu_slab);
++ struct kmem_cache *s;
++ struct kmem_cache_cpu *c;
++ struct slub_flush_work *sfw;
++
++ sfw = container_of(w, struct slub_flush_work, work);
++
++ s = sfw->s;
++ c = this_cpu_ptr(s->cpu_slab);
+
+ if (c->page)
+- flush_slab(s, c, false);
++ flush_slab(s, c, true);
+
+ unfreeze_partials(s);
+ }
+
+-static bool has_cpu_slab(int cpu, void *info)
++static bool has_cpu_slab(int cpu, struct kmem_cache *s)
+ {
+- struct kmem_cache *s = info;
+ struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
+
+ return c->page || slub_percpu_partial(c);
+ }
+
++static DEFINE_MUTEX(flush_lock);
++static DEFINE_PER_CPU(struct slub_flush_work, slub_flush);
++
+ static void flush_all(struct kmem_cache *s)
+ {
+- on_each_cpu_cond(has_cpu_slab, flush_cpu_slab, s, 1);
++ struct slub_flush_work *sfw;
++ unsigned int cpu;
++
++ cpus_read_lock();
++ mutex_lock(&flush_lock);
++
++ for_each_online_cpu(cpu) {
++ sfw = &per_cpu(slub_flush, cpu);
++ if (!has_cpu_slab(cpu, s)) {
++ sfw->skip = true;
++ continue;
++ }
++ INIT_WORK(&sfw->work, flush_cpu_slab);
++ sfw->skip = false;
++ sfw->s = s;
++ schedule_work_on(cpu, &sfw->work);
++ }
++
++ for_each_online_cpu(cpu) {
++ sfw = &per_cpu(slub_flush, cpu);
++ if (sfw->skip)
++ continue;
++ flush_work(&sfw->work);
++ }
++
++ mutex_unlock(&flush_lock);
++ cpus_read_unlock();
+ }
+
+ /*