|
@@ -829,68 +829,12 @@ static bool task_will_free_mem(struct task_struct *task)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static void oom_kill_process(struct oom_control *oc, const char *message)
|
|
|
+static void __oom_kill_process(struct task_struct *victim)
|
|
|
{
|
|
|
- struct task_struct *p = oc->chosen;
|
|
|
- unsigned int points = oc->chosen_points;
|
|
|
- struct task_struct *victim = p;
|
|
|
- struct task_struct *child;
|
|
|
- struct task_struct *t;
|
|
|
+ struct task_struct *p;
|
|
|
struct mm_struct *mm;
|
|
|
- unsigned int victim_points = 0;
|
|
|
- static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
|
|
|
- DEFAULT_RATELIMIT_BURST);
|
|
|
bool can_oom_reap = true;
|
|
|
|
|
|
- /*
|
|
|
- * If the task is already exiting, don't alarm the sysadmin or kill
|
|
|
- * its children or threads, just give it access to memory reserves
|
|
|
- * so it can die quickly
|
|
|
- */
|
|
|
- task_lock(p);
|
|
|
- if (task_will_free_mem(p)) {
|
|
|
- mark_oom_victim(p);
|
|
|
- wake_oom_reaper(p);
|
|
|
- task_unlock(p);
|
|
|
- put_task_struct(p);
|
|
|
- return;
|
|
|
- }
|
|
|
- task_unlock(p);
|
|
|
-
|
|
|
- if (__ratelimit(&oom_rs))
|
|
|
- dump_header(oc, p);
|
|
|
-
|
|
|
- pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n",
|
|
|
- message, task_pid_nr(p), p->comm, points);
|
|
|
-
|
|
|
- /*
|
|
|
- * If any of p's children has a different mm and is eligible for kill,
|
|
|
- * the one with the highest oom_badness() score is sacrificed for its
|
|
|
- * parent. This attempts to lose the minimal amount of work done while
|
|
|
- * still freeing memory.
|
|
|
- */
|
|
|
- read_lock(&tasklist_lock);
|
|
|
- for_each_thread(p, t) {
|
|
|
- list_for_each_entry(child, &t->children, sibling) {
|
|
|
- unsigned int child_points;
|
|
|
-
|
|
|
- if (process_shares_mm(child, p->mm))
|
|
|
- continue;
|
|
|
- /*
|
|
|
- * oom_badness() returns 0 if the thread is unkillable
|
|
|
- */
|
|
|
- child_points = oom_badness(child,
|
|
|
- oc->memcg, oc->nodemask, oc->totalpages);
|
|
|
- if (child_points > victim_points) {
|
|
|
- put_task_struct(victim);
|
|
|
- victim = child;
|
|
|
- victim_points = child_points;
|
|
|
- get_task_struct(victim);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- read_unlock(&tasklist_lock);
|
|
|
-
|
|
|
p = find_lock_task_mm(victim);
|
|
|
if (!p) {
|
|
|
put_task_struct(victim);
|
|
@@ -964,6 +908,69 @@ static void oom_kill_process(struct oom_control *oc, const char *message)
|
|
|
}
|
|
|
#undef K
|
|
|
|
|
|
+static void oom_kill_process(struct oom_control *oc, const char *message)
|
|
|
+{
|
|
|
+ struct task_struct *p = oc->chosen;
|
|
|
+ unsigned int points = oc->chosen_points;
|
|
|
+ struct task_struct *victim = p;
|
|
|
+ struct task_struct *child;
|
|
|
+ struct task_struct *t;
|
|
|
+ unsigned int victim_points = 0;
|
|
|
+ static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL,
|
|
|
+ DEFAULT_RATELIMIT_BURST);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the task is already exiting, don't alarm the sysadmin or kill
|
|
|
+ * its children or threads, just give it access to memory reserves
|
|
|
+ * so it can die quickly
|
|
|
+ */
|
|
|
+ task_lock(p);
|
|
|
+ if (task_will_free_mem(p)) {
|
|
|
+ mark_oom_victim(p);
|
|
|
+ wake_oom_reaper(p);
|
|
|
+ task_unlock(p);
|
|
|
+ put_task_struct(p);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ task_unlock(p);
|
|
|
+
|
|
|
+ if (__ratelimit(&oom_rs))
|
|
|
+ dump_header(oc, p);
|
|
|
+
|
|
|
+ pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n",
|
|
|
+ message, task_pid_nr(p), p->comm, points);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If any of p's children has a different mm and is eligible for kill,
|
|
|
+ * the one with the highest oom_badness() score is sacrificed for its
|
|
|
+ * parent. This attempts to lose the minimal amount of work done while
|
|
|
+ * still freeing memory.
|
|
|
+ */
|
|
|
+ read_lock(&tasklist_lock);
|
|
|
+ for_each_thread(p, t) {
|
|
|
+ list_for_each_entry(child, &t->children, sibling) {
|
|
|
+ unsigned int child_points;
|
|
|
+
|
|
|
+ if (process_shares_mm(child, p->mm))
|
|
|
+ continue;
|
|
|
+ /*
|
|
|
+ * oom_badness() returns 0 if the thread is unkillable
|
|
|
+ */
|
|
|
+ child_points = oom_badness(child,
|
|
|
+ oc->memcg, oc->nodemask, oc->totalpages);
|
|
|
+ if (child_points > victim_points) {
|
|
|
+ put_task_struct(victim);
|
|
|
+ victim = child;
|
|
|
+ victim_points = child_points;
|
|
|
+ get_task_struct(victim);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ read_unlock(&tasklist_lock);
|
|
|
+
|
|
|
+ __oom_kill_process(victim);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Determines whether the kernel must panic because of the panic_on_oom sysctl.
|
|
|
*/
|