|
@@ -85,6 +85,7 @@ void leave_mm(int cpu)
|
|
|
|
|
|
switch_mm(NULL, &init_mm, NULL);
|
|
|
}
|
|
|
+EXPORT_SYMBOL_GPL(leave_mm);
|
|
|
|
|
|
void switch_mm(struct mm_struct *prev, struct mm_struct *next,
|
|
|
struct task_struct *tsk)
|
|
@@ -195,12 +196,22 @@ void switch_mm_irqs_off(struct mm_struct *prev, struct mm_struct *next,
|
|
|
this_cpu_write(cpu_tlbstate.ctxs[new_asid].ctx_id, next->context.ctx_id);
|
|
|
this_cpu_write(cpu_tlbstate.ctxs[new_asid].tlb_gen, next_tlb_gen);
|
|
|
write_cr3(build_cr3(next, new_asid));
|
|
|
- trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH,
|
|
|
- TLB_FLUSH_ALL);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * NB: This gets called via leave_mm() in the idle path
|
|
|
+ * where RCU functions differently. Tracing normally
|
|
|
+ * uses RCU, so we need to use the _rcuidle variant.
|
|
|
+ *
|
|
|
+ * (There is no good reason for this. The idle code should
|
|
|
+ * be rearranged to call this before rcu_idle_enter().)
|
|
|
+ */
|
|
|
+ trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, TLB_FLUSH_ALL);
|
|
|
} else {
|
|
|
/* The new ASID is already up to date. */
|
|
|
write_cr3(build_cr3_noflush(next, new_asid));
|
|
|
- trace_tlb_flush(TLB_FLUSH_ON_TASK_SWITCH, 0);
|
|
|
+
|
|
|
+ /* See above wrt _rcuidle. */
|
|
|
+ trace_tlb_flush_rcuidle(TLB_FLUSH_ON_TASK_SWITCH, 0);
|
|
|
}
|
|
|
|
|
|
this_cpu_write(cpu_tlbstate.loaded_mm, next);
|