]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - mm/oom_kill.c
Merge branches 'for-4.6/upstream-fixes', 'for-4.7/asus', 'for-4.7/hidraw' and 'for...
[mirror_ubuntu-artful-kernel.git] / mm / oom_kill.c
index 2830b1c6483ee051151c464e0dd3fc83460290f8..86349586eacbac5022affca24ebaa2b57d19aa15 100644 (file)
@@ -410,14 +410,18 @@ static DECLARE_WAIT_QUEUE_HEAD(oom_victims_wait);
 
 bool oom_killer_disabled __read_mostly;
 
+#define K(x) ((x) << (PAGE_SHIFT-10))
+
 #ifdef CONFIG_MMU
 /*
  * OOM Reaper kernel thread which tries to reap the memory used by the OOM
  * victim (if that is possible) to help the OOM killer to move on.
  */
 static struct task_struct *oom_reaper_th;
-static struct task_struct *task_to_reap;
 static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait);
+static struct task_struct *oom_reaper_list;
+static DEFINE_SPINLOCK(oom_reaper_lock);
+
 
 static bool __oom_reap_task(struct task_struct *tsk)
 {
@@ -479,6 +483,11 @@ static bool __oom_reap_task(struct task_struct *tsk)
                                         &details);
        }
        tlb_finish_mmu(&tlb, 0, -1);
+       pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
+                       task_pid_nr(tsk), tsk->comm,
+                       K(get_mm_counter(mm, MM_ANONPAGES)),
+                       K(get_mm_counter(mm, MM_FILEPAGES)),
+                       K(get_mm_counter(mm, MM_SHMEMPAGES)));
        up_read(&mm->mmap_sem);
 
        /*
@@ -495,27 +504,42 @@ out:
        return ret;
 }
 
+#define MAX_OOM_REAP_RETRIES 10
 static void oom_reap_task(struct task_struct *tsk)
 {
        int attempts = 0;
 
        /* Retry the down_read_trylock(mmap_sem) a few times */
-       while (attempts++ < 10 && !__oom_reap_task(tsk))
+       while (attempts++ < MAX_OOM_REAP_RETRIES && !__oom_reap_task(tsk))
                schedule_timeout_idle(HZ/10);
 
+       if (attempts > MAX_OOM_REAP_RETRIES) {
+               pr_info("oom_reaper: unable to reap pid:%d (%s)\n",
+                               task_pid_nr(tsk), tsk->comm);
+               debug_show_all_locks();
+       }
+
        /* Drop a reference taken by wake_oom_reaper */
        put_task_struct(tsk);
 }
 
 static int oom_reaper(void *unused)
 {
+       set_freezable();
+
        while (true) {
-               struct task_struct *tsk;
+               struct task_struct *tsk = NULL;
+
+               wait_event_freezable(oom_reaper_wait, oom_reaper_list != NULL);
+               spin_lock(&oom_reaper_lock);
+               if (oom_reaper_list != NULL) {
+                       tsk = oom_reaper_list;
+                       oom_reaper_list = tsk->oom_reaper_list;
+               }
+               spin_unlock(&oom_reaper_lock);
 
-               wait_event_freezable(oom_reaper_wait,
-                                    (tsk = READ_ONCE(task_to_reap)));
-               oom_reap_task(tsk);
-               WRITE_ONCE(task_to_reap, NULL);
+               if (tsk)
+                       oom_reap_task(tsk);
        }
 
        return 0;
@@ -523,23 +547,20 @@ static int oom_reaper(void *unused)
 
 static void wake_oom_reaper(struct task_struct *tsk)
 {
-       struct task_struct *old_tsk;
-
        if (!oom_reaper_th)
                return;
 
+       /* tsk is already queued? */
+       if (tsk == oom_reaper_list || tsk->oom_reaper_list)
+               return;
+
        get_task_struct(tsk);
 
-       /*
-        * Make sure that only a single mm is ever queued for the reaper
-        * because multiple are not necessary and the operation might be
-        * disruptive so better reduce it to the bare minimum.
-        */
-       old_tsk = cmpxchg(&task_to_reap, NULL, tsk);
-       if (!old_tsk)
-               wake_up(&oom_reaper_wait);
-       else
-               put_task_struct(tsk);
+       spin_lock(&oom_reaper_lock);
+       tsk->oom_reaper_list = oom_reaper_list;
+       oom_reaper_list = tsk;
+       spin_unlock(&oom_reaper_lock);
+       wake_up(&oom_reaper_wait);
 }
 
 static int __init oom_init(void)
@@ -649,7 +670,6 @@ static bool process_shares_mm(struct task_struct *p, struct mm_struct *mm)
        return false;
 }
 
-#define K(x) ((x) << (PAGE_SHIFT-10))
 /*
  * Must be called while holding a reference to p, which will be released upon
  * returning.