diff options
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.patch | 109 |
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(); + } + + /* |