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