]> rtime.felk.cvut.cz Git - can-eth-gw-linux.git/blobdiff - mm/oom_kill.c
mm, oom: cleanup pagefault oom handler
[can-eth-gw-linux.git] / mm / oom_kill.c
index 79e0f3e24831212d7be9635d7ee214755ed22ba3..0e30ff7b21c541253eb0f983d8c9a07ca298a70f 100644 (file)
@@ -44,48 +44,6 @@ int sysctl_oom_kill_allocating_task;
 int sysctl_oom_dump_tasks = 1;
 static DEFINE_SPINLOCK(zone_scan_lock);
 
-/*
- * compare_swap_oom_score_adj() - compare and swap current's oom_score_adj
- * @old_val: old oom_score_adj for compare
- * @new_val: new oom_score_adj for swap
- *
- * Sets the oom_score_adj value for current to @new_val iff its present value is
- * @old_val.  Usually used to reinstate a previous value to prevent racing with
- * userspacing tuning the value in the interim.
- */
-void compare_swap_oom_score_adj(int old_val, int new_val)
-{
-       struct sighand_struct *sighand = current->sighand;
-
-       spin_lock_irq(&sighand->siglock);
-       if (current->signal->oom_score_adj == old_val)
-               current->signal->oom_score_adj = new_val;
-       trace_oom_score_adj_update(current);
-       spin_unlock_irq(&sighand->siglock);
-}
-
-/**
- * test_set_oom_score_adj() - set current's oom_score_adj and return old value
- * @new_val: new oom_score_adj value
- *
- * Sets the oom_score_adj value for current to @new_val with proper
- * synchronization and returns the old value.  Usually used to temporarily
- * set a value, save the old value in the caller, and then reinstate it later.
- */
-int test_set_oom_score_adj(int new_val)
-{
-       struct sighand_struct *sighand = current->sighand;
-       int old_val;
-
-       spin_lock_irq(&sighand->siglock);
-       old_val = current->signal->oom_score_adj;
-       current->signal->oom_score_adj = new_val;
-       trace_oom_score_adj_update(current);
-       spin_unlock_irq(&sighand->siglock);
-
-       return old_val;
-}
-
 #ifdef CONFIG_NUMA
 /**
  * has_intersects_mems_allowed() - check task eligiblity for kill
@@ -193,7 +151,7 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
        if (!p)
                return 0;
 
-       adj = p->signal->oom_score_adj;
+       adj = (long)p->signal->oom_score_adj;
        if (adj == OOM_SCORE_ADJ_MIN) {
                task_unlock(p);
                return 0;
@@ -257,7 +215,7 @@ static enum oom_constraint constrained_alloc(struct zonelist *zonelist,
         * the page allocator means a mempolicy is in effect.  Cpuset policy
         * is enforced in get_page_from_freelist().
         */
-       if (nodemask && !nodes_subset(node_states[N_HIGH_MEMORY], *nodemask)) {
+       if (nodemask && !nodes_subset(node_states[N_MEMORY], *nodemask)) {
                *totalpages = total_swap_pages;
                for_each_node_mask(nid, *nodemask)
                        *totalpages += node_spanned_pages(nid);
@@ -310,26 +268,20 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task,
        if (!task->mm)
                return OOM_SCAN_CONTINUE;
 
-       if (task->flags & PF_EXITING) {
+       /*
+        * If task is allocating a lot of memory and has been marked to be
+        * killed first if it triggers an oom, then select it.
+        */
+       if (oom_task_origin(task))
+               return OOM_SCAN_SELECT;
+
+       if (task->flags & PF_EXITING && !force_kill) {
                /*
-                * If task is current and is in the process of releasing memory,
-                * allow the "kill" to set TIF_MEMDIE, which will allow it to
-                * access memory reserves.  Otherwise, it may stall forever.
-                *
-                * The iteration isn't broken here, however, in case other
-                * threads are found to have already been oom killed.
+                * If this task is not being ptraced on exit, then wait for it
+                * to finish before killing some other task unnecessarily.
                 */
-               if (task == current)
-                       return OOM_SCAN_SELECT;
-               else if (!force_kill) {
-                       /*
-                        * If this task is not being ptraced on exit, then wait
-                        * for it to finish before killing some other task
-                        * unnecessarily.
-                        */
-                       if (!(task->group_leader->ptrace & PT_TRACE_EXIT))
-                               return OOM_SCAN_ABORT;
-               }
+               if (!(task->group_leader->ptrace & PT_TRACE_EXIT))
+                       return OOM_SCAN_ABORT;
        }
        return OOM_SCAN_OK;
 }
@@ -412,7 +364,7 @@ static void dump_tasks(const struct mem_cgroup *memcg, const nodemask_t *nodemas
                        continue;
                }
 
-               pr_info("[%5d] %5d %5d %8lu %8lu %7lu %8lu         %5d %s\n",
+               pr_info("[%5d] %5d %5d %8lu %8lu %7lu %8lu         %5hd %s\n",
                        task->pid, from_kuid(&init_user_ns, task_uid(task)),
                        task->tgid, task->mm->total_vm, get_mm_rss(task->mm),
                        task->mm->nr_ptes,
@@ -428,7 +380,7 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order,
 {
        task_lock(current);
        pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, "
-               "oom_score_adj=%d\n",
+               "oom_score_adj=%hd\n",
                current->comm, gfp_mask, order,
                current->signal->oom_score_adj);
        cpuset_print_task_mems_allowed(current);
@@ -639,43 +591,6 @@ void clear_zonelist_oom(struct zonelist *zonelist, gfp_t gfp_mask)
        spin_unlock(&zone_scan_lock);
 }
 
-/*
- * Try to acquire the oom killer lock for all system zones.  Returns zero if a
- * parallel oom killing is taking place, otherwise locks all zones and returns
- * non-zero.
- */
-static int try_set_system_oom(void)
-{
-       struct zone *zone;
-       int ret = 1;
-
-       spin_lock(&zone_scan_lock);
-       for_each_populated_zone(zone)
-               if (zone_is_oom_locked(zone)) {
-                       ret = 0;
-                       goto out;
-               }
-       for_each_populated_zone(zone)
-               zone_set_flag(zone, ZONE_OOM_LOCKED);
-out:
-       spin_unlock(&zone_scan_lock);
-       return ret;
-}
-
-/*
- * Clears ZONE_OOM_LOCKED for all system zones so that failed allocation
- * attempts or page faults may now recall the oom killer, if necessary.
- */
-static void clear_system_oom(void)
-{
-       struct zone *zone;
-
-       spin_lock(&zone_scan_lock);
-       for_each_populated_zone(zone)
-               zone_clear_flag(zone, ZONE_OOM_LOCKED);
-       spin_unlock(&zone_scan_lock);
-}
-
 /**
  * out_of_memory - kill the "best" process when we run out of memory
  * @zonelist: zonelist pointer
@@ -706,11 +621,11 @@ void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask,
                return;
 
        /*
-        * If current has a pending SIGKILL, then automatically select it.  The
-        * goal is to allow it to allocate so that it may quickly exit and free
-        * its memory.
+        * If current has a pending SIGKILL or is exiting, then automatically
+        * select it.  The goal is to allow it to allocate so that it may
+        * quickly exit and free its memory.
         */
-       if (fatal_signal_pending(current)) {
+       if (fatal_signal_pending(current) || current->flags & PF_EXITING) {
                set_thread_flag(TIF_MEMDIE);
                return;
        }
@@ -756,15 +671,17 @@ out:
 
 /*
  * The pagefault handler calls here because it is out of memory, so kill a
- * memory-hogging task.  If a populated zone has ZONE_OOM_LOCKED set, a parallel
- * oom killing is already in progress so do nothing.  If a task is found with
- * TIF_MEMDIE set, it has been killed so do nothing and allow it to exit.
+ * memory-hogging task.  If any populated zone has ZONE_OOM_LOCKED set, a
+ * parallel oom killing is already in progress so do nothing.
  */
 void pagefault_out_of_memory(void)
 {
-       if (try_set_system_oom()) {
+       struct zonelist *zonelist = node_zonelist(first_online_node,
+                                                 GFP_KERNEL);
+
+       if (try_set_zonelist_oom(zonelist, GFP_KERNEL)) {
                out_of_memory(NULL, 0, 0, NULL, false);
-               clear_system_oom();
+               clear_zonelist_oom(zonelist, GFP_KERNEL);
        }
        schedule_timeout_killable(1);
 }