From 05d5ad4d0af90e05d63da7945282c7f5dc18f682 Mon Sep 17 00:00:00 2001 From: Liam Mark Date: Thu, 7 Feb 2013 14:31:36 -0800 Subject: [PATCH] android/lowmemorykiller: Ignore tasks with freed mm A killed task can stay in the task list long after its memory has been returned to the system, therefore ignore any tasks whose mm struct has been freed. Change-Id: I76394b203b4ab2312437c839976f0ecb7b6dde4e CRs-fixed: 450383 Signed-off-by: Liam Mark --- arch/arm/include/asm/thread_info.h | 1 + drivers/staging/android/lowmemorykiller.c | 10 ++++++++-- include/linux/sched.h | 2 +- kernel/exit.c | 6 +++++- kernel/fork.c | 5 ++++- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 1995d1a84060..fde592f68b6d 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -157,6 +157,7 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ #define TIF_RESTORE_SIGMASK 20 #define TIF_SWITCH_MM 22 /* deferred switch_mm */ +#define TIF_MM_RELEASED 23 /* task MM has been released */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index f4d6c7c27e6c..e632d171d857 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -211,6 +211,10 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) if (tsk->flags & PF_KTHREAD) continue; + /* if task no longer has any memory ignore it */ + if (test_task_flag(tsk, TIF_MM_RELEASED)) + continue; + if (time_before_eq(jiffies, lowmem_deathpending_timeout)) { if (test_task_flag(tsk, TIF_MEMDIE)) { rcu_read_unlock(); @@ -264,12 +268,14 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) send_sig(SIGKILL, selected, 0); set_tsk_thread_flag(selected, TIF_MEMDIE); rem -= selected_tasksize; + rcu_read_unlock(); /* give the system time to free up the memory */ msleep_interruptible(20); - } + } else + rcu_read_unlock(); + lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", nr_to_scan, sc->gfp_mask, rem); - rcu_read_unlock(); mutex_unlock(&scan_mutex); return rem; } diff --git a/include/linux/sched.h b/include/linux/sched.h index d6c4ea89daa4..54dc0d8152d6 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2107,7 +2107,7 @@ static inline void mmdrop(struct mm_struct * mm) } /* mmput gets rid of the mappings and all user-space */ -extern void mmput(struct mm_struct *); +extern int mmput(struct mm_struct *); /* Grab a reference to a task's mm, if it is not already going away */ extern struct mm_struct *get_task_mm(struct task_struct *task); /* diff --git a/kernel/exit.c b/kernel/exit.c index 677bc87316e1..52adc3e91994 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -454,6 +454,7 @@ static void exit_mm(struct task_struct * tsk) { struct mm_struct *mm = tsk->mm; struct core_state *core_state; + int mm_released; mm_release(tsk, mm); if (!mm) @@ -499,7 +500,10 @@ static void exit_mm(struct task_struct * tsk) enter_lazy_tlb(mm, current); task_unlock(tsk); mm_update_next_owner(mm); - mmput(mm); + + mm_released = mmput(mm); + if (mm_released) + set_tsk_thread_flag(tsk, TIF_MM_RELEASED); } /* diff --git a/kernel/fork.c b/kernel/fork.c index 41671a5d637d..bf502679cec2 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -623,8 +623,9 @@ EXPORT_SYMBOL_GPL(__mmdrop); /* * Decrement the use count and release all resources for an mm. */ -void mmput(struct mm_struct *mm) +int mmput(struct mm_struct *mm) { + int mm_freed = 0; might_sleep(); if (atomic_dec_and_test(&mm->mm_users)) { @@ -642,7 +643,9 @@ void mmput(struct mm_struct *mm) if (mm->binfmt) module_put(mm->binfmt->module); mmdrop(mm); + mm_freed = 1; } + return mm_freed; } EXPORT_SYMBOL_GPL(mmput);