mm, oom_adj: don't loop through tasks in __set_oom_adj when not necessary
[linux-block.git] / kernel / fork.c
index ede26e5a6097041926dbdb73fa2c568b0e4e5176..50c90d3681179125aa89665d9375a5c2dfc20ac2 100644 (file)
@@ -1812,6 +1812,25 @@ static __always_inline void delayed_free_task(struct task_struct *tsk)
                free_task(tsk);
 }
 
+static void copy_oom_score_adj(u64 clone_flags, struct task_struct *tsk)
+{
+       /* Skip if kernel thread */
+       if (!tsk->mm)
+               return;
+
+       /* Skip if spawning a thread or using vfork */
+       if ((clone_flags & (CLONE_VM | CLONE_THREAD | CLONE_VFORK)) != CLONE_VM)
+               return;
+
+       /* We need to synchronize with __set_oom_adj */
+       mutex_lock(&oom_adj_mutex);
+       set_bit(MMF_MULTIPROCESS, &tsk->mm->flags);
+       /* Update the values in case they were changed after copy_signal */
+       tsk->signal->oom_score_adj = current->signal->oom_score_adj;
+       tsk->signal->oom_score_adj_min = current->signal->oom_score_adj_min;
+       mutex_unlock(&oom_adj_mutex);
+}
+
 /*
  * This creates a new process as a copy of the old one,
  * but does not actually start it yet.
@@ -2288,6 +2307,8 @@ static __latent_entropy struct task_struct *copy_process(
        trace_task_newtask(p, clone_flags);
        uprobe_copy_process(p, clone_flags);
 
+       copy_oom_score_adj(clone_flags, p);
+
        return p;
 
 bad_fork_cancel_cgroup: