lowmemorykiller.c revision 31d59a4198f3f07da8250dfb5b698eacfaf612e5
1/* drivers/misc/lowmemorykiller.c 2 * 3 * Copyright (C) 2007-2008 Google, Inc. 4 * 5 * This software is licensed under the terms of the GNU General Public 6 * License version 2, as published by the Free Software Foundation, and 7 * may be copied, distributed, and modified under those terms. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 */ 15 16#include <linux/module.h> 17#include <linux/kernel.h> 18#include <linux/mm.h> 19#include <linux/oom.h> 20#include <linux/sched.h> 21 22static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask); 23 24static struct shrinker lowmem_shrinker = { 25 .shrink = lowmem_shrink, 26 .seeks = DEFAULT_SEEKS * 16 27}; 28static uint32_t lowmem_debug_level = 2; 29static int lowmem_adj[6] = { 30 0, 31 1, 32 6, 33 12, 34}; 35static int lowmem_adj_size = 4; 36static size_t lowmem_minfree[6] = { 37 3*512, // 6MB 38 2*1024, // 8MB 39 4*1024, // 16MB 40 16*1024, // 64MB 41}; 42static int lowmem_minfree_size = 4; 43 44#define lowmem_print(level, x...) do { if(lowmem_debug_level >= (level)) printk(x); } while(0) 45 46module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); 47module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, S_IRUGO | S_IWUSR); 48module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, S_IRUGO | S_IWUSR); 49module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); 50 51static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) 52{ 53 struct task_struct *p; 54 struct task_struct *selected = NULL; 55 int rem = 0; 56 int tasksize; 57 int i; 58 int min_adj = OOM_ADJUST_MAX + 1; 59 int selected_tasksize = 0; 60 int array_size = ARRAY_SIZE(lowmem_adj); 61 int other_free = global_page_state(NR_FREE_PAGES); 62 int other_file = global_page_state(NR_FILE_PAGES); 63 if(lowmem_adj_size < array_size) 64 array_size = lowmem_adj_size; 65 if(lowmem_minfree_size < array_size) 66 array_size = lowmem_minfree_size; 67 for(i = 0; i < array_size; i++) { 68 if (other_free < lowmem_minfree[i] && 69 other_file < lowmem_minfree[i]) { 70 min_adj = lowmem_adj[i]; 71 break; 72 } 73 } 74 if(nr_to_scan > 0) 75 lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n", nr_to_scan, gfp_mask, other_free, other_file, min_adj); 76 rem = global_page_state(NR_ACTIVE_ANON) + 77 global_page_state(NR_ACTIVE_FILE) + 78 global_page_state(NR_INACTIVE_ANON) + 79 global_page_state(NR_INACTIVE_FILE); 80 if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) { 81 lowmem_print(5, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); 82 return rem; 83 } 84 85 read_lock(&tasklist_lock); 86 for_each_process(p) { 87 if (p->oomkilladj < min_adj || !p->mm) 88 continue; 89 tasksize = get_mm_rss(p->mm); 90 if (tasksize <= 0) 91 continue; 92 if (selected) { 93 if (p->oomkilladj < selected->oomkilladj) 94 continue; 95 if (p->oomkilladj == selected->oomkilladj && 96 tasksize <= selected_tasksize) 97 continue; 98 } 99 selected = p; 100 selected_tasksize = tasksize; 101 lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", 102 p->pid, p->comm, p->oomkilladj, tasksize); 103 } 104 if(selected != NULL) { 105 lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", 106 selected->pid, selected->comm, 107 selected->oomkilladj, selected_tasksize); 108 force_sig(SIGKILL, selected); 109 rem -= selected_tasksize; 110 } 111 lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", nr_to_scan, gfp_mask, rem); 112 read_unlock(&tasklist_lock); 113 return rem; 114} 115 116static int __init lowmem_init(void) 117{ 118 register_shrinker(&lowmem_shrinker); 119 return 0; 120} 121 122static void __exit lowmem_exit(void) 123{ 124 unregister_shrinker(&lowmem_shrinker); 125} 126 127module_init(lowmem_init); 128module_exit(lowmem_exit); 129 130MODULE_LICENSE("GPL"); 131 132