From 19ac1a8740d14bd0c098fc8ef8d398f132776204 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 | 2 +- drivers/staging/android/lowmemorykiller.c | 10 ++++++++-- include/linux/sched.h | 2 +- kernel/exit.c | 6 +++++- kernel/fork.c | 5 ++++- 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index 0f04d84582e..67d644334b0 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -153,7 +153,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_SECCOMP 21 - +#define TIF_MM_RELEASED 22 /* task MM has been released */ #define _TIF_SIGPENDING (1 << TIF_SIGPENDING) #define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) #define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 5bac37d8cae..4a9dd1b4a06 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -283,6 +283,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(); @@ -327,12 +331,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 0a1428ec1d1..67889bfedd9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2304,7 +2304,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 d8bd3b425fa..6096e809bf9 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -639,6 +639,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) @@ -683,7 +684,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 c0bf8c7002a..0de735c9b6b 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -581,8 +581,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)) { @@ -600,7 +601,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);