Matt Fleming 52f948
Subject: sched: Move mmdrop to RCU on RT
Matt Fleming 52f948
From: Thomas Gleixner <tglx@linutronix.de>
Matt Fleming 52f948
Date: Mon, 06 Jun 2011 12:20:33 +0200
Daniel Wagner c00dcb
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git
Daniel Wagner c00dcb
Git-commit: da77ceac3d20f27310a07a7c346a4ee6b40d6c28
Matt Fleming 52f948
Patch-mainline: Queued in subsystem maintainer repository
Matt Fleming 52f948
References: SLE Realtime Extension
Matt Fleming 52f948
Matt Fleming 52f948
Takes sleeping locks and calls into the memory allocator, so nothing
Matt Fleming 52f948
we want to do in task switch and oder atomic contexts.
Matt Fleming 52f948
Matt Fleming 52f948
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Matt Fleming 52f948
Signed-off-by: Daniel Wagner <dwagner@suse.de>
Matt Fleming 52f948
---
Matt Fleming 52f948
 include/linux/mm_types.h |    4 ++++
Matt Fleming 52f948
 include/linux/sched/mm.h |   11 +++++++++++
Matt Fleming 52f948
 kernel/fork.c            |   13 +++++++++++++
Matt Fleming 52f948
 kernel/sched/core.c      |   18 ++++++++++++++++--
Matt Fleming 52f948
 4 files changed, 44 insertions(+), 2 deletions(-)
Matt Fleming 52f948
Matt Fleming 52f948
--- a/include/linux/mm_types.h
Matt Fleming 52f948
+++ b/include/linux/mm_types.h
Matt Fleming 52f948
@@ -12,6 +12,7 @@
Matt Fleming 52f948
 #include <linux/completion.h>
Matt Fleming 52f948
 #include <linux/cpumask.h>
Matt Fleming 52f948
 #include <linux/uprobes.h>
Matt Fleming 52f948
+#include <linux/rcupdate.h>
Matt Fleming 52f948
 #include <linux/page-flags-layout.h>
Matt Fleming 52f948
 #include <linux/workqueue.h>
Matt Fleming 52f948
 
Daniel Wagner c00dcb
@@ -520,6 +521,9 @@ struct mm_struct {
Matt Fleming 52f948
 		bool tlb_flush_batched;
Matt Fleming 52f948
 #endif
Matt Fleming 52f948
 		struct uprobes_state uprobes_state;
Daniel Wagner fdf974
+#ifdef CONFIG_PREEMPT_RT
Matt Fleming 52f948
+		struct rcu_head delayed_drop;
Matt Fleming 52f948
+#endif
Matt Fleming 52f948
 #ifdef CONFIG_HUGETLB_PAGE
Matt Fleming 52f948
 		atomic_long_t hugetlb_usage;
Matt Fleming 52f948
 #endif
Matt Fleming 52f948
--- a/include/linux/sched/mm.h
Matt Fleming 52f948
+++ b/include/linux/sched/mm.h
Matt Fleming 52f948
@@ -49,6 +49,17 @@ static inline void mmdrop(struct mm_stru
Matt Fleming 52f948
 		__mmdrop(mm);
Matt Fleming 52f948
 }
Matt Fleming 52f948
 
Daniel Wagner fdf974
+#ifdef CONFIG_PREEMPT_RT
Matt Fleming 52f948
+extern void __mmdrop_delayed(struct rcu_head *rhp);
Matt Fleming 52f948
+static inline void mmdrop_delayed(struct mm_struct *mm)
Matt Fleming 52f948
+{
Matt Fleming 52f948
+	if (atomic_dec_and_test(&mm->mm_count))
Matt Fleming 52f948
+		call_rcu(&mm->delayed_drop, __mmdrop_delayed);
Matt Fleming 52f948
+}
Matt Fleming 52f948
+#else
Matt Fleming 52f948
+# define mmdrop_delayed(mm)	mmdrop(mm)
Matt Fleming 52f948
+#endif
Matt Fleming 52f948
+
Matt Fleming 52f948
 /*
Matt Fleming 52f948
  * This has to be called after a get_task_mm()/mmget_not_zero()
Matt Fleming 52f948
  * followed by taking the mmap_sem for writing before modifying the
Matt Fleming 52f948
--- a/kernel/fork.c
Matt Fleming 52f948
+++ b/kernel/fork.c
Daniel Wagner c00dcb
@@ -696,6 +696,19 @@ void __mmdrop(struct mm_struct *mm)
Matt Fleming 52f948
 }
Matt Fleming 52f948
 EXPORT_SYMBOL_GPL(__mmdrop);
Matt Fleming 52f948
 
Daniel Wagner fdf974
+#ifdef CONFIG_PREEMPT_RT
Matt Fleming 52f948
+/*
Matt Fleming 52f948
+ * RCU callback for delayed mm drop. Not strictly rcu, but we don't
Matt Fleming 52f948
+ * want another facility to make this work.
Matt Fleming 52f948
+ */
Matt Fleming 52f948
+void __mmdrop_delayed(struct rcu_head *rhp)
Matt Fleming 52f948
+{
Matt Fleming 52f948
+	struct mm_struct *mm = container_of(rhp, struct mm_struct, delayed_drop);
Matt Fleming 52f948
+
Matt Fleming 52f948
+	__mmdrop(mm);
Matt Fleming 52f948
+}
Matt Fleming 52f948
+#endif
Matt Fleming 52f948
+
Matt Fleming 52f948
 static void mmdrop_async_fn(struct work_struct *work)
Matt Fleming 52f948
 {
Matt Fleming 52f948
 	struct mm_struct *mm;
Matt Fleming 52f948
--- a/kernel/sched/core.c
Matt Fleming 52f948
+++ b/kernel/sched/core.c
Daniel Wagner c00dcb
@@ -3241,9 +3241,13 @@ static struct rq *finish_task_switch(str
Matt Fleming 52f948
 	 *   provided by mmdrop(),
Matt Fleming 52f948
 	 * - a sync_core for SYNC_CORE.
Matt Fleming 52f948
 	 */
Matt Fleming 52f948
+	/*
Matt Fleming 52f948
+	 * We use mmdrop_delayed() here so we don't have to do the
Matt Fleming 52f948
+	 * full __mmdrop() when we are the last user.
Matt Fleming 52f948
+	 */
Matt Fleming 52f948
 	if (mm) {
Matt Fleming 52f948
 		membarrier_mm_sync_core_before_usermode(mm);
Matt Fleming 52f948
-		mmdrop(mm);
Matt Fleming 52f948
+		mmdrop_delayed(mm);
Matt Fleming 52f948
 	}
Matt Fleming 52f948
 	if (unlikely(prev_state == TASK_DEAD)) {
Matt Fleming 52f948
 		if (prev->sched_class->task_dead)
Daniel Wagner c00dcb
@@ -6173,6 +6177,8 @@ void sched_setnuma(struct task_struct *p
Matt Fleming 52f948
 #endif /* CONFIG_NUMA_BALANCING */
Matt Fleming 52f948
 
Matt Fleming 52f948
 #ifdef CONFIG_HOTPLUG_CPU
Matt Fleming 52f948
+static DEFINE_PER_CPU(struct mm_struct *, idle_last_mm);
Matt Fleming 52f948
+
Matt Fleming 52f948
 /*
Matt Fleming 52f948
  * Ensure that the idle task is using init_mm right before its CPU goes
Matt Fleming 52f948
  * offline.
Daniel Wagner c00dcb
@@ -6188,7 +6194,11 @@ void idle_task_exit(void)
Matt Fleming 52f948
 		current->active_mm = &init_mm;
Matt Fleming 52f948
 		finish_arch_post_lock_switch();
Matt Fleming 52f948
 	}
Matt Fleming 52f948
-	mmdrop(mm);
Matt Fleming 52f948
+	/*
Matt Fleming 52f948
+	 * Defer the cleanup to an alive cpu. On RT we can neither
Matt Fleming 52f948
+	 * call mmdrop() nor mmdrop_delayed() from here.
Matt Fleming 52f948
+	 */
Matt Fleming 52f948
+	per_cpu(idle_last_mm, smp_processor_id()) = mm;
Matt Fleming 52f948
 }
Matt Fleming 52f948
 
Matt Fleming 52f948
 /*
Daniel Wagner c00dcb
@@ -6494,6 +6504,10 @@ int sched_cpu_dying(unsigned int cpu)
Matt Fleming 52f948
 	update_max_interval();
Matt Fleming 52f948
 	nohz_balance_exit_idle(rq);
Matt Fleming 52f948
 	hrtick_clear(rq);
Matt Fleming 52f948
+	if (per_cpu(idle_last_mm, cpu)) {
Matt Fleming 52f948
+		mmdrop_delayed(per_cpu(idle_last_mm, cpu));
Matt Fleming 52f948
+		per_cpu(idle_last_mm, cpu) = NULL;
Matt Fleming 52f948
+	}
Matt Fleming 52f948
 	return 0;
Matt Fleming 52f948
 }
Matt Fleming 52f948
 #endif