lowmemorykiller.c revision edd540ea92954f896bfb7ee0ebf5dfdde6e6cb41
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 uint32_t lowmem_debug_level = 2; 23static int lowmem_adj[6] = { 24 0, 25 1, 26 6, 27 12, 28}; 29static int lowmem_adj_size = 4; 30static size_t lowmem_minfree[6] = { 31 3 * 512, /* 6MB */ 32 2 * 1024, /* 8MB */ 33 4 * 1024, /* 16MB */ 34 16 * 1024, /* 64MB */ 35}; 36static int lowmem_minfree_size = 4; 37 38#define lowmem_print(level, x...) \ 39 do { \ 40 if (lowmem_debug_level >= (level)) \ 41 printk(x); \ 42 } while (0) 43 44module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR); 45module_param_array_named(adj, lowmem_adj, int, &lowmem_adj_size, 46 S_IRUGO | S_IWUSR); 47module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size, 48 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 struct mm_struct *mm; 94 int oom_adj; 95 96 task_lock(p); 97 mm = p->mm; 98 if (!mm) { 99 task_unlock(p); 100 continue; 101 } 102 oom_adj = mm->oom_adj; 103 if (oom_adj < min_adj) { 104 task_unlock(p); 105 continue; 106 } 107 tasksize = get_mm_rss(mm); 108 task_unlock(p); 109 if (tasksize <= 0) 110 continue; 111 if (selected) { 112 if (oom_adj < selected_oom_adj) 113 continue; 114 if (oom_adj == selected_oom_adj && 115 tasksize <= selected_tasksize) 116 continue; 117 } 118 selected = p; 119 selected_tasksize = tasksize; 120 selected_oom_adj = oom_adj; 121 lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n", 122 p->pid, p->comm, oom_adj, tasksize); 123 } 124 if (selected) { 125 lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", 126 selected->pid, selected->comm, 127 selected_oom_adj, selected_tasksize); 128 force_sig(SIGKILL, selected); 129 rem -= selected_tasksize; 130 } 131 lowmem_print(4, "lowmem_shrink %d, %x, return %d\n", 132 nr_to_scan, gfp_mask, rem); 133 read_unlock(&tasklist_lock); 134 return rem; 135} 136 137static struct shrinker lowmem_shrinker = { 138 .shrink = lowmem_shrink, 139 .seeks = DEFAULT_SEEKS * 16 140}; 141 142static int __init lowmem_init(void) 143{ 144 register_shrinker(&lowmem_shrinker); 145 return 0; 146} 147 148static void __exit lowmem_exit(void) 149{ 150 unregister_shrinker(&lowmem_shrinker); 151} 152 153module_init(lowmem_init); 154module_exit(lowmem_exit); 155 156MODULE_LICENSE("GPL"); 157 158