The OOM killer uses MMF_OOM_SKIP to avoid running on an mm that has started __mmput(); it only uses the mmgrab() reference to ensure that the mm_struct itself stays alive.
This means that we don't need a full mmgrab() reference, which will keep the pgd (and potentially also some pmd pages) alive and can't be cleaned up from RCU callback context; we can use an mm_ref() reference instead. Signed-off-by: Jann Horn <ja...@google.com> --- kernel/fork.c | 6 +----- mm/oom_kill.c | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/kernel/fork.c b/kernel/fork.c index fcdd1ace79e4..59c119b03351 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -686,12 +686,8 @@ static inline void free_signal_struct(struct signal_struct *sig) { taskstats_tgid_free(sig); sched_autogroup_exit(sig); - /* - * __mmdrop is not safe to call from softirq context on x86 due to - * pgd_dtor so postpone it to the async context - */ if (sig->oom_mm) - mmdrop_async(sig->oom_mm); + mm_unref(sig->oom_mm); kmem_cache_free(signal_cachep, sig); } diff --git a/mm/oom_kill.c b/mm/oom_kill.c index e90f25d6385d..12967f54fbcf 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -704,7 +704,7 @@ static void mark_oom_victim(struct task_struct *tsk) /* oom_mm is bound to the signal struct life time. */ if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) { - mmgrab(tsk->signal->oom_mm); + mm_ref(tsk->signal->oom_mm); set_bit(MMF_OOM_VICTIM, &mm->flags); } -- 2.29.0.rc1.297.gfa9743e501-goog