@@ -1117,9 +1117,10 @@ static int exec_mmap(struct mm_struct *mm)
setmax_mm_hiwater_rss(&tsk->signal->maxrss, old_mm);
mm_update_next_owner(old_mm);
mmput(old_mm);
- return 0;
+ } else {
+ exit_lazy_tlb(active_mm, tsk);
+ mmdrop(active_mm);
}
- mmdrop(active_mm);
return 0;
}
@@ -24,6 +24,26 @@ static inline void enter_lazy_tlb(struct mm_struct *mm,
}
#endif
+/*
+ * exit_lazy_tlb - Called after switching away from a lazy TLB mode mm.
+ *
+ * mm: the lazy mm context that was switched away from
+ * tsk: the task that was switched to non-lazy mm
+ *
+ * tsk->mm will not be NULL.
+ *
+ * Note this is not symmetrical to enter_lazy_tlb, this is not
+ * called when tasks switch into the lazy mm, it's called after the
+ * lazy mm becomes non-lazy (either switched to a different mm or the
+ * owner of the mm returns).
+ */
+#ifndef exit_lazy_tlb
+static inline void exit_lazy_tlb(struct mm_struct *mm,
+ struct task_struct *tsk)
+{
+}
+#endif
+
/**
* init_new_context - Initialize context of a new mm_struct.
* @tsk: task struct for the mm
@@ -1253,6 +1253,7 @@ void kthread_use_mm(struct mm_struct *mm)
if (active_mm != mm)
mmdrop(active_mm);
+ exit_lazy_tlb(active_mm, tsk);
to_kthread(tsk)->oldfs = get_fs();
set_fs(USER_DS);
@@ -3439,6 +3439,8 @@ context_switch(struct rq *rq, struct task_struct *prev,
switch_mm_irqs_off(prev->active_mm, next->mm, next);
if (!prev->mm) { // from kernel
+ exit_lazy_tlb(prev->active_mm, next);
+
/* will mmdrop() in finish_task_switch(). */
rq->prev_mm = prev->active_mm;
prev->active_mm = NULL;
Signed-off-by: Nicholas Piggin <npiggin@gmail.com> --- fs/exec.c | 5 +++-- include/asm-generic/mmu_context.h | 20 ++++++++++++++++++++ kernel/kthread.c | 1 + kernel/sched/core.c | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-)