diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/android/Kconfig | 6 | ||||
-rw-r--r-- | drivers/staging/android/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/android/lowmemorykiller.c | 119 |
3 files changed, 126 insertions, 0 deletions
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 502c283eedc..934f6f2019b 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -77,4 +77,10 @@ config ANDROID_TIMED_GPIO depends on GENERIC_GPIO default n +config ANDROID_LOW_MEMORY_KILLER + bool "Android Low Memory Killer" + default N + ---help--- + Register processes to be killed when memory is low + endmenu diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile index 7ea6fbe92f4..95209d6273a 100644 --- a/drivers/staging/android/Makefile +++ b/drivers/staging/android/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o obj-$(CONFIG_ANDROID_LOGGER) += logger.o obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o +obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c new file mode 100644 index 00000000000..3715d56ca96 --- /dev/null +++ b/drivers/staging/android/lowmemorykiller.c @@ -0,0 +1,119 @@ +/* drivers/misc/lowmemorykiller.c + * + * Copyright (C) 2007-2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/oom.h> +#include <linux/sched.h> + +static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask); + +static struct shrinker lowmem_shrinker = { + .shrink = lowmem_shrink, + .seeks = DEFAULT_SEEKS * 16 +}; +static uint32_t lowmem_debug_level = 2; +static int lowmem_adj[6] = { + 0, + 1, + 6, + 12, +}; +static int lowmem_adj_size = 4; +static size_t lowmem_minfree[6] = { + 3*512, // 6MB + 2*1024, // 8MB + 4*1024, // 16MB + 16*1024, // 64MB +}; +static int lowmem_minfree_size = 4; + +#define lowmem_print(level, x...) do { if(lowmem_debug_level >= (level)) printk(x); } while(0) + +module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); +module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, S_IRUGO | S_IWUSR); +module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, S_IRUGO | S_IWUSR); +module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); + +static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) +{ + struct task_struct *p; + struct task_struct *selected = NULL; + int rem = 0; + int tasksize; + int i; + int min_adj = OOM_ADJUST_MAX + 1; + int selected_tasksize = 0; + int array_size = ARRAY_SIZE(lowmem_adj); + int other_free = global_page_state(NR_FREE_PAGES) + global_page_state(NR_FILE_PAGES); + if(lowmem_adj_size < array_size) + array_size = lowmem_adj_size; + if(lowmem_minfree_size < array_size) + array_size = lowmem_minfree_size; + for(i = 0; i < array_size; i++) { + if(other_free < lowmem_minfree[i]) { + min_adj = lowmem_adj[i]; + break; + } + } + if(nr_to_scan > 0) + lowmem_print(3, "lowmem_shrink %d, %x, ofree %d, ma %d\n", nr_to_scan, gfp_mask, other_free, min_adj); + read_lock(&tasklist_lock); + for_each_process(p) { + if(p->oomkilladj >= 0 && p->mm) { + tasksize = get_mm_rss(p->mm); + if(nr_to_scan > 0 && tasksize > 0 && p->oomkilladj >= min_adj) { + if(selected == NULL || + p->oomkilladj > selected->oomkilladj || + (p->oomkilladj == selected->oomkilladj && + tasksize > selected_tasksize)) { + selected = p; + selected_tasksize = tasksize; + lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", + p->pid, p->comm, p->oomkilladj, tasksize); + } + } + rem += tasksize; + } + } + if(selected != NULL) { + lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", + selected->pid, selected->comm, + selected->oomkilladj, selected_tasksize); + force_sig(SIGKILL, selected); + rem -= selected_tasksize; + } + lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); + read_unlock(&tasklist_lock); + return rem; +} + +static int __init lowmem_init(void) +{ + register_shrinker(&lowmem_shrinker); + return 0; +} + +static void __exit lowmem_exit(void) +{ + unregister_shrinker(&lowmem_shrinker); +} + +module_init(lowmem_init); +module_exit(lowmem_exit); + +MODULE_LICENSE("GPL"); + |