lowmemorykiller.c revision 1dbb5765acc7a6fe4bc1957c001037cc9d02ae03
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...) \ 45 do { \ 46 if (lowmem_debug_level >= (level)) \ 47 printk(x); \ 48 } while (0) 49 50module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); 51module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, 52 S_IRUGO | S_IWUSR); 53module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, 54 S_IRUGO | S_IWUSR); 55module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR); 56 57static int lowmem_shrink(int nr_to_scan, gfp_t gfp_mask) 58{ 59 struct task_struct *p; 60 struct task_struct *selected = NULL; 61 int rem = 0; 62 int tasksize; 63 int i; 64 int min_adj = OOM_ADJUST_MAX + 1; 65 int selected_tasksize = 0; 66 int selected_oom_adj; 67 int array_size = ARRAY_SIZE(lowmem_adj); 68 int other_free = global_page_state(NR_FREE_PAGES); 69 int other_file = global_page_state(NR_FILE_PAGES); 70 71 if (lowmem_adj_size < array_size) 72 array_size = lowmem_adj_size; 73 if (lowmem_minfree_size < array_size) 74 array_size = lowmem_minfree_size; 75 for (i = 0; i < array_size; i++) { 76 if (other_free < lowmem_minfree[i] && 77 other_file < lowmem_minfree[i]) { 78 min_adj = lowmem_adj[i]; 79 break; 80 } 81 } 82 if (nr_to_scan > 0) 83 lowmem_print(3, "lowmem_shrink %d, %x, ofree %d %d, ma %d\n", 84 nr_to_scan, gfp_mask, other_free, other_file, 85 min_adj); 86 rem = global_page_state(NR_ACTIVE_ANON) + 87 global_page_state(NR_ACTIVE_FILE) + 88 global_page_state(NR_INACTIVE_ANON) + 89 global_page_state(NR_INACTIVE_FILE); 90 if (nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) { 91 lowmem_print(5, "lowmem_shrink %d, %x, return %d\n", 92 nr_to_scan, gfp_mask, rem); 93 return rem; 94 } 95 selected_oom_adj = min_adj; 96 97 read_lock(&tasklist_lock); 98 for_each_process(p) { 99 int oom_adj; 100 101 task_lock(p); 102 if (!p->mm) { 103 task_unlock(p); 104 continue; 105 } 106 oom_adj = p->oomkilladj; 107 if (oom_adj < min_adj) { 108 task_unlock(p); 109 continue; 110 } 111 tasksize = get_mm_rss(p->mm); 112 task_unlock(p); 113 if (tasksize <= 0) 114 continue; 115 if (selected) { 116 if (oom_adj < selected_oom_adj) 117 continue; 118 if (oom_adj == selected_oom_adj && 119 tasksize <= selected_tasksize) 120 continue; 121 } 122 selected = p; 123 selected_tasksize = tasksize; 124 selected_oom_adj = oom_adj; 125 lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", 126 p->pid, p->comm, oom_adj, tasksize); 127 } 128 if (selected) { 129 lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", 130 selected->pid, selected->comm, 131 selected_oom_adj, selected_tasksize); 132 force_sig(SIGKILL, selected); 133 rem -= selected_tasksize; 134 } 135 lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", 136 nr_to_scan, gfp_mask, rem); 137 read_unlock(&tasklist_lock); 138 return rem; 139} 140 141static int __init lowmem_init(void) 142{ 143 register_shrinker(&lowmem_shrinker); 144 return 0; 145} 146 147static void __exit lowmem_exit(void) 148{ 149 unregister_shrinker(&lowmem_shrinker); 150} 151 152module_init(lowmem_init); 153module_exit(lowmem_exit); 154 155MODULE_LICENSE("GPL"); 156 157