Loading drivers/staging/android/Kconfig +23 −1 Original line number Diff line number Diff line Loading @@ -38,15 +38,37 @@ config ANDROID_LOW_MEMORY_KILLER scripts (/init.rc), and it defines priority values with minimum free memory size for each priority. config ANDROID_LOW_MEMORY_KILLER_TNG bool "Android Low Memory Killer TNG" select OOM_SCORE_NOTIFIER ---help--- The NEXT generation (TNG) lowmemorykiller. Registers processes to be killed when low memory conditions, this is useful as there is no particular swap space on android. The registered process will kills according to the priorities in android init scripts (/init.rc), and it defines priority values with minimum free memory size for each priority. config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES bool "Android Low Memory Killer: detect oom_adj values" depends on ANDROID_LOW_MEMORY_KILLER depends on ANDROID_LOW_MEMORY_KILLER || ANDROID_LOW_MEMORY_KILLER_TNG default y ---help--- Detect oom_adj values written to /sys/module/lowmemorykiller/parameters/adj and convert them to oom_score_adj values. config ANDROID_LOW_MEMORY_KILLER_STATS bool "Android Low Memory Killer: collect statistics" default n help Create a file in /proc/lmkstats that includes collected statistics about kills, scans and counts and interaction with the shrinker. Its content will be different depending on lmk implementation used in TNG lowmemorykiller. config SYNC bool "Synchronization framework" default n Loading drivers/staging/android/Makefile +3 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,9 @@ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o lowmemorykiller_tng := lowmemorykiller_tng.o lowmemorykiller_tasks.o lowmemorykiller_oom.o lowmemorykiller_vmpressure.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG) += lowmemorykiller_tng obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER_STATS) += lowmemorykiller_stats.o obj-$(CONFIG_SYNC) += sync.o sync_debug.o obj-$(CONFIG_SW_SYNC) += sw_sync.o obj-$(CONFIG_ONESHOT_SYNC) += oneshot_sync.o Loading drivers/staging/android/lowmemorykiller.c +61 −57 Original line number Diff line number Diff line Loading @@ -29,6 +29,11 @@ * GNU General Public License for more details. * */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading @@ -42,8 +47,6 @@ #include <linux/rcupdate.h> #include <linux/profile.h> #include <linux/notifier.h> #include <linux/mutex.h> #include <linux/delay.h> #include <linux/swap.h> #include <linux/fs.h> #include <linux/cpuset.h> Loading @@ -56,6 +59,7 @@ #define CREATE_TRACE_POINTS #include <trace/events/almk.h> #include <trace/events/lmk.h> #ifdef CONFIG_HIGHMEM #define _ZONE ZONE_HIGHMEM Loading @@ -66,15 +70,20 @@ #define CREATE_TRACE_POINTS #include "trace/lowmemorykiller.h" static uint32_t lowmem_debug_level = 1; static short lowmem_adj[6] = { #include "lowmemorykiller_stats.h" #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG #include "lowmemorykiller_tng.h" #endif uint32_t lowmem_debug_level = 1; short lowmem_adj[6] = { 0, 1, 6, 12, }; static int lowmem_adj_size = 4; static int lowmem_minfree[6] = { int lowmem_minfree[6] = { 3 * 512, /* 6MB */ 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ Loading @@ -85,6 +94,17 @@ static int lmk_fast_run = 1; static unsigned long lowmem_deathpending_timeout; int lowmem_min_param_size(void) { int array_size = ARRAY_SIZE(lowmem_adj); if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; return array_size; } #define lowmem_print(level, x...) \ do { \ if (lowmem_debug_level >= (level)) \ Loading Loading @@ -228,6 +248,7 @@ static void lmk_event_init(void) static unsigned long lowmem_count(struct shrinker *s, struct shrink_control *sc) { lmk_inc_stats(LMK_COUNT); return global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + Loading Loading @@ -288,12 +309,17 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, unsigned long pressure = action; int array_size = ARRAY_SIZE(lowmem_adj); if (!enable_adaptive_lmk) if (!enable_adaptive_lmk) { #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG balance_cache(); #endif return 0; } if (pressure >= 95) { other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); Loading @@ -307,6 +333,7 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); Loading @@ -331,7 +358,9 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, trace_almk_vmpressure(pressure, other_free, other_file); atomic_set(&shift_adj, 0); } #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG balance_cache(); #endif return 0; } Loading @@ -355,24 +384,6 @@ static int test_task_flag(struct task_struct *p, int flag) return 0; } static int test_task_state(struct task_struct *p, int state) { struct task_struct *t; for_each_thread(p, t) { task_lock(t); if (t->state & state) { task_unlock(t); return 1; } task_unlock(t); } return 0; } static DEFINE_MUTEX(scan_mutex); int can_use_cma_pages(gfp_t gfp_mask) { int can_use = 0; Loading Loading @@ -555,25 +566,16 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) int selected_tasksize = 0; short selected_oom_score_adj; int array_size = ARRAY_SIZE(lowmem_adj); int other_free; int other_file; if (!mutex_trylock(&scan_mutex)) return 0; other_free = global_page_state(NR_FREE_PAGES); if (global_page_state(NR_SHMEM) + total_swapcache_pages() < global_page_state(NR_FILE_PAGES) + zcache_pages()) other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - int other_free = global_page_state(NR_FREE_PAGES); int other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); else other_file = 0; other_file = (other_file < 0) ? 0 : other_file; tune_lmk_param(&other_free, &other_file, sc); lmk_inc_stats(LMK_SCAN); if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) Loading @@ -596,7 +598,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) trace_almk_shrink(0, ret, other_free, other_file, 0); lowmem_print(5, "lowmem_scan %lu, %x, return 0\n", sc->nr_to_scan, sc->gfp_mask); mutex_unlock(&scan_mutex); trace_lmk_remain_scan(0, sc->nr_to_scan, sc->gfp_mask); return 0; } Loading @@ -614,10 +616,16 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) if (test_task_flag(tsk, TIF_MM_RELEASED)) continue; /* Ignore task if coredump in progress */ if (tsk->mm && tsk->mm->core_state) continue; if (time_before_eq(jiffies, lowmem_deathpending_timeout)) { if (test_task_flag(tsk, TIF_MEMDIE)) { rcu_read_unlock(); mutex_unlock(&scan_mutex); trace_lmk_remain_scan(0, sc->nr_to_scan, sc->gfp_mask); lmk_inc_stats(LMK_TIMEOUT); return 0; } } Loading Loading @@ -650,17 +658,6 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) } if (selected) { long cache_size, cache_limit, free; if (test_task_flag(selected, TIF_MEMDIE) && (test_task_state(selected, TASK_UNINTERRUPTIBLE))) { lowmem_print(2, "'%s' (%d) is already killed\n", selected->comm, selected->pid); rcu_read_unlock(); mutex_unlock(&scan_mutex); return 0; } task_lock(selected); send_sig(SIGKILL, selected, 0); /* Loading Loading @@ -709,21 +706,24 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; trace_lmk_sigkill(selected->pid, selected->comm, selected_oom_score_adj, selected_tasksize, sc->gfp_mask); rcu_read_unlock(); get_task_struct(selected); /* give the system time to free up the memory */ msleep_interruptible(20); trace_almk_shrink(selected_tasksize, ret, other_free, other_file, selected_oom_score_adj); lmk_inc_stats(LMK_KILL); } else { trace_almk_shrink(1, ret, other_free, other_file, 0); lmk_inc_stats(LMK_WASTE); rcu_read_unlock(); } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); mutex_unlock(&scan_mutex); trace_lmk_remain_scan(rem, sc->nr_to_scan, sc->gfp_mask); if (selected) { handle_lmk_event(selected, selected_tasksize, min_score_adj); Loading @@ -741,9 +741,13 @@ static struct shrinker lowmem_shrinker = { static int __init lowmem_init(void) { #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG lowmem_init_tng(&lowmem_shrinker); #endif register_shrinker(&lowmem_shrinker); vmpressure_notifier_register(&lmk_vmpr_nb); lmk_event_init(); init_procfs_lmk(); return 0; } device_initcall(lowmem_init); Loading drivers/staging/android/lowmemorykiller.h 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 Sony Mobile Communications Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. */ #ifndef __LOWMEMORYKILLER_H #define __LOWMEMORYKILLER_H #include <linux/version.h> /* The lowest score LMK is using */ #define LMK_SCORE_THRESHOLD 0 extern u32 lowmem_debug_level; #define lowmem_print(level, x...) \ do { \ if (lowmem_debug_level >= (level)) \ pr_info(x); \ } while (0) int __init lowmemorykiller_register_oom_notifier(void); struct calculated_params { long selected_tasksize; long minfree; int other_file; int other_free; int dynamic_max_queue_len; short selected_oom_score_adj; short min_score_adj; }; int kill_needed(int level, gfp_t mask, struct calculated_params *cp); void print_obituary(struct task_struct *doomed, struct calculated_params *cp, gfp_t gfp_mask); void balance_cache(void); ssize_t get_task_rss(struct task_struct *tsk); /* kernel does not have a task_trylock and * to make it more obvious what the code do * we create a help function for it. * see sched.h for task_lock and task_unlock */ static inline int task_trylock_lmk(struct task_struct *p) { return spin_trylock(&p->alloc_lock); } /* maybe not exact version, we need something betwwen 3.18 and 4.4. * using LINUX_VERSION_CODE like this will give a warning. * it it not OK for mainline but for multiple kernel version patches * I think it is OK. */ #if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 0, 0) #define LMK_TAG_TASK_DIE(x) set_tsk_thread_flag(x, TIF_MEMDIE) #elif LINUX_VERSION_CODE <= KERNEL_VERSION(4, 5, 0) #define LMK_TAG_TASK_DIE(x) mark_oom_victim(x) #else #define LMK_TAG_TASK_DIE(x) \ do { \ if (x->mm) \ task_set_lmk_waiting(x);\ if (!test_bit(MMF_OOM_SKIP, &x->mm->flags) && \ oom_reaper) { \ mark_lmk_victim(x); \ wake_oom_reaper(x);\ } \ } while (0) #endif #endif drivers/staging/android/lowmemorykiller_oom.c 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * lowmemorykiller_oom * * Author: Peter Enderborg <peter.enderborg@sonymobile.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * Copyright (C) 2017 Sony Mobile Communications Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. */ /* add fake print format with original module name */ #define pr_fmt(fmt) "lowmemorykiller: " fmt #include <linux/mm.h> #include <linux/slab.h> #include <linux/oom.h> #include <trace/events/lmk.h> #include "lowmemorykiller.h" #include "lowmemorykiller_stats.h" #include "lowmemorykiller_tasks.h" /** * lowmemorykiller_oom_notify - OOM notifier * @self: notifier block struct * @notused: not used * @parm: returned - number of pages freed * * Return value: * NOTIFY_OK **/ static int lowmemorykiller_oom_notify(struct notifier_block *self, unsigned long notused, void *param) { struct lmk_rb_watch *lrw; unsigned long *nfreed = param; lowmem_print(2, "oom notify event\n"); *nfreed = 0; lmk_inc_stats(LMK_OOM_COUNT); spin_lock_bh(&lmk_task_lock); lrw = __lmk_task_first(); if (lrw) { struct task_struct *selected = lrw->tsk; struct lmk_death_pending_entry *ldpt; if (!task_trylock_lmk(selected)) { lmk_inc_stats(LMK_ERROR); lowmem_print(1, "Failed to lock task.\n"); lmk_inc_stats(LMK_BUSY); goto unlock_out; } /* move to kill pending set */ ldpt = kmem_cache_alloc(lmk_dp_cache, GFP_ATOMIC); ldpt->tsk = selected; __lmk_death_pending_add(ldpt); if (!__lmk_task_remove(selected, lrw->key)) WARN_ON(1); spin_unlock_bh(&lmk_task_lock); *nfreed = get_task_rss(lrw->tsk); send_sig(SIGKILL, selected, 0); LMK_TAG_TASK_DIE(selected); trace_lmk_sigkill(selected->pid, selected->comm, -1, *nfreed, 0); task_unlock(selected); lmk_inc_stats(LMK_OOM_KILL_COUNT); goto out; } unlock_out: spin_unlock_bh(&lmk_task_lock); out: return NOTIFY_OK; } static struct notifier_block lowmemorykiller_oom_nb = { .notifier_call = lowmemorykiller_oom_notify }; int __init lowmemorykiller_register_oom_notifier(void) { register_oom_notifier(&lowmemorykiller_oom_nb); return 0; } Loading
drivers/staging/android/Kconfig +23 −1 Original line number Diff line number Diff line Loading @@ -38,15 +38,37 @@ config ANDROID_LOW_MEMORY_KILLER scripts (/init.rc), and it defines priority values with minimum free memory size for each priority. config ANDROID_LOW_MEMORY_KILLER_TNG bool "Android Low Memory Killer TNG" select OOM_SCORE_NOTIFIER ---help--- The NEXT generation (TNG) lowmemorykiller. Registers processes to be killed when low memory conditions, this is useful as there is no particular swap space on android. The registered process will kills according to the priorities in android init scripts (/init.rc), and it defines priority values with minimum free memory size for each priority. config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES bool "Android Low Memory Killer: detect oom_adj values" depends on ANDROID_LOW_MEMORY_KILLER depends on ANDROID_LOW_MEMORY_KILLER || ANDROID_LOW_MEMORY_KILLER_TNG default y ---help--- Detect oom_adj values written to /sys/module/lowmemorykiller/parameters/adj and convert them to oom_score_adj values. config ANDROID_LOW_MEMORY_KILLER_STATS bool "Android Low Memory Killer: collect statistics" default n help Create a file in /proc/lmkstats that includes collected statistics about kills, scans and counts and interaction with the shrinker. Its content will be different depending on lmk implementation used in TNG lowmemorykiller. config SYNC bool "Synchronization framework" default n Loading
drivers/staging/android/Makefile +3 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,9 @@ obj-$(CONFIG_ASHMEM) += ashmem.o obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o lowmemorykiller_tng := lowmemorykiller_tng.o lowmemorykiller_tasks.o lowmemorykiller_oom.o lowmemorykiller_vmpressure.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG) += lowmemorykiller_tng obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER_STATS) += lowmemorykiller_stats.o obj-$(CONFIG_SYNC) += sync.o sync_debug.o obj-$(CONFIG_SW_SYNC) += sw_sync.o obj-$(CONFIG_ONESHOT_SYNC) += oneshot_sync.o Loading
drivers/staging/android/lowmemorykiller.c +61 −57 Original line number Diff line number Diff line Loading @@ -29,6 +29,11 @@ * GNU General Public License for more details. * */ /* * NOTE: This file has been modified by Sony Mobile Communications Inc. * Modifications are Copyright (c) 2015 Sony Mobile Communications Inc, * and licensed under the license of the file. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt Loading @@ -42,8 +47,6 @@ #include <linux/rcupdate.h> #include <linux/profile.h> #include <linux/notifier.h> #include <linux/mutex.h> #include <linux/delay.h> #include <linux/swap.h> #include <linux/fs.h> #include <linux/cpuset.h> Loading @@ -56,6 +59,7 @@ #define CREATE_TRACE_POINTS #include <trace/events/almk.h> #include <trace/events/lmk.h> #ifdef CONFIG_HIGHMEM #define _ZONE ZONE_HIGHMEM Loading @@ -66,15 +70,20 @@ #define CREATE_TRACE_POINTS #include "trace/lowmemorykiller.h" static uint32_t lowmem_debug_level = 1; static short lowmem_adj[6] = { #include "lowmemorykiller_stats.h" #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG #include "lowmemorykiller_tng.h" #endif uint32_t lowmem_debug_level = 1; short lowmem_adj[6] = { 0, 1, 6, 12, }; static int lowmem_adj_size = 4; static int lowmem_minfree[6] = { int lowmem_minfree[6] = { 3 * 512, /* 6MB */ 2 * 1024, /* 8MB */ 4 * 1024, /* 16MB */ Loading @@ -85,6 +94,17 @@ static int lmk_fast_run = 1; static unsigned long lowmem_deathpending_timeout; int lowmem_min_param_size(void) { int array_size = ARRAY_SIZE(lowmem_adj); if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) array_size = lowmem_minfree_size; return array_size; } #define lowmem_print(level, x...) \ do { \ if (lowmem_debug_level >= (level)) \ Loading Loading @@ -228,6 +248,7 @@ static void lmk_event_init(void) static unsigned long lowmem_count(struct shrinker *s, struct shrink_control *sc) { lmk_inc_stats(LMK_COUNT); return global_page_state(NR_ACTIVE_ANON) + global_page_state(NR_ACTIVE_FILE) + global_page_state(NR_INACTIVE_ANON) + Loading Loading @@ -288,12 +309,17 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, unsigned long pressure = action; int array_size = ARRAY_SIZE(lowmem_adj); if (!enable_adaptive_lmk) if (!enable_adaptive_lmk) { #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG balance_cache(); #endif return 0; } if (pressure >= 95) { other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); Loading @@ -307,6 +333,7 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); other_free = global_page_state(NR_FREE_PAGES); Loading @@ -331,7 +358,9 @@ static int lmk_vmpressure_notifier(struct notifier_block *nb, trace_almk_vmpressure(pressure, other_free, other_file); atomic_set(&shift_adj, 0); } #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG balance_cache(); #endif return 0; } Loading @@ -355,24 +384,6 @@ static int test_task_flag(struct task_struct *p, int flag) return 0; } static int test_task_state(struct task_struct *p, int state) { struct task_struct *t; for_each_thread(p, t) { task_lock(t); if (t->state & state) { task_unlock(t); return 1; } task_unlock(t); } return 0; } static DEFINE_MUTEX(scan_mutex); int can_use_cma_pages(gfp_t gfp_mask) { int can_use = 0; Loading Loading @@ -555,25 +566,16 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) int selected_tasksize = 0; short selected_oom_score_adj; int array_size = ARRAY_SIZE(lowmem_adj); int other_free; int other_file; if (!mutex_trylock(&scan_mutex)) return 0; other_free = global_page_state(NR_FREE_PAGES); if (global_page_state(NR_SHMEM) + total_swapcache_pages() < global_page_state(NR_FILE_PAGES) + zcache_pages()) other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - int other_free = global_page_state(NR_FREE_PAGES); int other_file = global_page_state(NR_FILE_PAGES) + zcache_pages() - global_page_state(NR_SHMEM) - global_page_state(NR_UNEVICTABLE) - total_swapcache_pages(); else other_file = 0; other_file = (other_file < 0) ? 0 : other_file; tune_lmk_param(&other_free, &other_file, sc); lmk_inc_stats(LMK_SCAN); if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; if (lowmem_minfree_size < array_size) Loading @@ -596,7 +598,7 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) trace_almk_shrink(0, ret, other_free, other_file, 0); lowmem_print(5, "lowmem_scan %lu, %x, return 0\n", sc->nr_to_scan, sc->gfp_mask); mutex_unlock(&scan_mutex); trace_lmk_remain_scan(0, sc->nr_to_scan, sc->gfp_mask); return 0; } Loading @@ -614,10 +616,16 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) if (test_task_flag(tsk, TIF_MM_RELEASED)) continue; /* Ignore task if coredump in progress */ if (tsk->mm && tsk->mm->core_state) continue; if (time_before_eq(jiffies, lowmem_deathpending_timeout)) { if (test_task_flag(tsk, TIF_MEMDIE)) { rcu_read_unlock(); mutex_unlock(&scan_mutex); trace_lmk_remain_scan(0, sc->nr_to_scan, sc->gfp_mask); lmk_inc_stats(LMK_TIMEOUT); return 0; } } Loading Loading @@ -650,17 +658,6 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) } if (selected) { long cache_size, cache_limit, free; if (test_task_flag(selected, TIF_MEMDIE) && (test_task_state(selected, TASK_UNINTERRUPTIBLE))) { lowmem_print(2, "'%s' (%d) is already killed\n", selected->comm, selected->pid); rcu_read_unlock(); mutex_unlock(&scan_mutex); return 0; } task_lock(selected); send_sig(SIGKILL, selected, 0); /* Loading Loading @@ -709,21 +706,24 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) lowmem_deathpending_timeout = jiffies + HZ; rem += selected_tasksize; trace_lmk_sigkill(selected->pid, selected->comm, selected_oom_score_adj, selected_tasksize, sc->gfp_mask); rcu_read_unlock(); get_task_struct(selected); /* give the system time to free up the memory */ msleep_interruptible(20); trace_almk_shrink(selected_tasksize, ret, other_free, other_file, selected_oom_score_adj); lmk_inc_stats(LMK_KILL); } else { trace_almk_shrink(1, ret, other_free, other_file, 0); lmk_inc_stats(LMK_WASTE); rcu_read_unlock(); } lowmem_print(4, "lowmem_scan %lu, %x, return %lu\n", sc->nr_to_scan, sc->gfp_mask, rem); mutex_unlock(&scan_mutex); trace_lmk_remain_scan(rem, sc->nr_to_scan, sc->gfp_mask); if (selected) { handle_lmk_event(selected, selected_tasksize, min_score_adj); Loading @@ -741,9 +741,13 @@ static struct shrinker lowmem_shrinker = { static int __init lowmem_init(void) { #ifdef CONFIG_ANDROID_LOW_MEMORY_KILLER_TNG lowmem_init_tng(&lowmem_shrinker); #endif register_shrinker(&lowmem_shrinker); vmpressure_notifier_register(&lmk_vmpr_nb); lmk_event_init(); init_procfs_lmk(); return 0; } device_initcall(lowmem_init); Loading
drivers/staging/android/lowmemorykiller.h 0 → 100644 +76 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 Sony Mobile Communications Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. */ #ifndef __LOWMEMORYKILLER_H #define __LOWMEMORYKILLER_H #include <linux/version.h> /* The lowest score LMK is using */ #define LMK_SCORE_THRESHOLD 0 extern u32 lowmem_debug_level; #define lowmem_print(level, x...) \ do { \ if (lowmem_debug_level >= (level)) \ pr_info(x); \ } while (0) int __init lowmemorykiller_register_oom_notifier(void); struct calculated_params { long selected_tasksize; long minfree; int other_file; int other_free; int dynamic_max_queue_len; short selected_oom_score_adj; short min_score_adj; }; int kill_needed(int level, gfp_t mask, struct calculated_params *cp); void print_obituary(struct task_struct *doomed, struct calculated_params *cp, gfp_t gfp_mask); void balance_cache(void); ssize_t get_task_rss(struct task_struct *tsk); /* kernel does not have a task_trylock and * to make it more obvious what the code do * we create a help function for it. * see sched.h for task_lock and task_unlock */ static inline int task_trylock_lmk(struct task_struct *p) { return spin_trylock(&p->alloc_lock); } /* maybe not exact version, we need something betwwen 3.18 and 4.4. * using LINUX_VERSION_CODE like this will give a warning. * it it not OK for mainline but for multiple kernel version patches * I think it is OK. */ #if LINUX_VERSION_CODE <= KERNEL_VERSION(4, 0, 0) #define LMK_TAG_TASK_DIE(x) set_tsk_thread_flag(x, TIF_MEMDIE) #elif LINUX_VERSION_CODE <= KERNEL_VERSION(4, 5, 0) #define LMK_TAG_TASK_DIE(x) mark_oom_victim(x) #else #define LMK_TAG_TASK_DIE(x) \ do { \ if (x->mm) \ task_set_lmk_waiting(x);\ if (!test_bit(MMF_OOM_SKIP, &x->mm->flags) && \ oom_reaper) { \ mark_lmk_victim(x); \ wake_oom_reaper(x);\ } \ } while (0) #endif #endif
drivers/staging/android/lowmemorykiller_oom.c 0 → 100644 +97 −0 Original line number Diff line number Diff line /* * lowmemorykiller_oom * * Author: Peter Enderborg <peter.enderborg@sonymobile.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /* * Copyright (C) 2017 Sony Mobile Communications Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2, as * published by the Free Software Foundation. */ /* add fake print format with original module name */ #define pr_fmt(fmt) "lowmemorykiller: " fmt #include <linux/mm.h> #include <linux/slab.h> #include <linux/oom.h> #include <trace/events/lmk.h> #include "lowmemorykiller.h" #include "lowmemorykiller_stats.h" #include "lowmemorykiller_tasks.h" /** * lowmemorykiller_oom_notify - OOM notifier * @self: notifier block struct * @notused: not used * @parm: returned - number of pages freed * * Return value: * NOTIFY_OK **/ static int lowmemorykiller_oom_notify(struct notifier_block *self, unsigned long notused, void *param) { struct lmk_rb_watch *lrw; unsigned long *nfreed = param; lowmem_print(2, "oom notify event\n"); *nfreed = 0; lmk_inc_stats(LMK_OOM_COUNT); spin_lock_bh(&lmk_task_lock); lrw = __lmk_task_first(); if (lrw) { struct task_struct *selected = lrw->tsk; struct lmk_death_pending_entry *ldpt; if (!task_trylock_lmk(selected)) { lmk_inc_stats(LMK_ERROR); lowmem_print(1, "Failed to lock task.\n"); lmk_inc_stats(LMK_BUSY); goto unlock_out; } /* move to kill pending set */ ldpt = kmem_cache_alloc(lmk_dp_cache, GFP_ATOMIC); ldpt->tsk = selected; __lmk_death_pending_add(ldpt); if (!__lmk_task_remove(selected, lrw->key)) WARN_ON(1); spin_unlock_bh(&lmk_task_lock); *nfreed = get_task_rss(lrw->tsk); send_sig(SIGKILL, selected, 0); LMK_TAG_TASK_DIE(selected); trace_lmk_sigkill(selected->pid, selected->comm, -1, *nfreed, 0); task_unlock(selected); lmk_inc_stats(LMK_OOM_KILL_COUNT); goto out; } unlock_out: spin_unlock_bh(&lmk_task_lock); out: return NOTIFY_OK; } static struct notifier_block lowmemorykiller_oom_nb = { .notifier_call = lowmemorykiller_oom_notify }; int __init lowmemorykiller_register_oom_notifier(void) { register_oom_notifier(&lowmemorykiller_oom_nb); return 0; }