linux/drivers/staging/android/lowmemorykiller.c
<<
>>
Prefs
   1/* drivers/misc/lowmemorykiller.c
   2 *
   3 * The lowmemorykiller driver lets user-space specify a set of memory thresholds
   4 * where processes with a range of oom_score_adj values will get killed. Specify
   5 * the minimum oom_score_adj values in
   6 * /sys/module/lowmemorykiller/parameters/adj and the number of free pages in
   7 * /sys/module/lowmemorykiller/parameters/minfree. Both files take a comma
   8 * separated list of numbers in ascending order.
   9 *
  10 * For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and
  11 * "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill
  12 * processes with a oom_score_adj value of 8 or higher when the free memory
  13 * drops below 4096 pages and kill processes with a oom_score_adj value of 0 or
  14 * higher when the free memory drops below 1024 pages.
  15 *
  16 * The driver considers memory used for caches to be free, but if a large
  17 * percentage of the cached memory is locked this can be very inaccurate
  18 * and processes may not get killed until the normal oom killer is triggered.
  19 *
  20 * Copyright (C) 2007-2008 Google, Inc.
  21 *
  22 * This software is licensed under the terms of the GNU General Public
  23 * License version 2, as published by the Free Software Foundation, and
  24 * may be copied, distributed, and modified under those terms.
  25 *
  26 * This program is distributed in the hope that it will be useful,
  27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  29 * GNU General Public License for more details.
  30 *
  31 */
  32
  33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  34
  35#include <linux/module.h>
  36#include <linux/kernel.h>
  37#include <linux/mm.h>
  38#include <linux/oom.h>
  39#include <linux/sched.h>
  40#include <linux/swap.h>
  41#include <linux/rcupdate.h>
  42#include <linux/profile.h>
  43#include <linux/notifier.h>
  44
  45static uint32_t lowmem_debug_level = 1;
  46static short lowmem_adj[6] = {
  47        0,
  48        1,
  49        6,
  50        12,
  51};
  52static int lowmem_adj_size = 4;
  53static int lowmem_minfree[6] = {
  54        3 * 512,        /* 6MB */
  55        2 * 1024,       /* 8MB */
  56        4 * 1024,       /* 16MB */
  57        16 * 1024,      /* 64MB */
  58};
  59static int lowmem_minfree_size = 4;
  60
  61static unsigned long lowmem_deathpending_timeout;
  62
  63#define lowmem_print(level, x...)                       \
  64        do {                                            \
  65                if (lowmem_debug_level >= (level))      \
  66                        pr_info(x);                     \
  67        } while (0)
  68
  69static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
  70{
  71        struct task_struct *tsk;
  72        struct task_struct *selected = NULL;
  73        int rem = 0;
  74        int tasksize;
  75        int i;
  76        short min_score_adj = OOM_SCORE_ADJ_MAX + 1;
  77        int selected_tasksize = 0;
  78        short selected_oom_score_adj;
  79        int array_size = ARRAY_SIZE(lowmem_adj);
  80        int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
  81        int other_file = global_page_state(NR_FILE_PAGES) -
  82                                                global_page_state(NR_SHMEM);
  83
  84        if (lowmem_adj_size < array_size)
  85                array_size = lowmem_adj_size;
  86        if (lowmem_minfree_size < array_size)
  87                array_size = lowmem_minfree_size;
  88        for (i = 0; i < array_size; i++) {
  89                if (other_free < lowmem_minfree[i] &&
  90                    other_file < lowmem_minfree[i]) {
  91                        min_score_adj = lowmem_adj[i];
  92                        break;
  93                }
  94        }
  95        if (sc->nr_to_scan > 0)
  96                lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %hd\n",
  97                                sc->nr_to_scan, sc->gfp_mask, other_free,
  98                                other_file, min_score_adj);
  99        rem = global_page_state(NR_ACTIVE_ANON) +
 100                global_page_state(NR_ACTIVE_FILE) +
 101                global_page_state(NR_INACTIVE_ANON) +
 102                global_page_state(NR_INACTIVE_FILE);
 103        if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
 104                lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",
 105                             sc->nr_to_scan, sc->gfp_mask, rem);
 106                return rem;
 107        }
 108        selected_oom_score_adj = min_score_adj;
 109
 110        rcu_read_lock();
 111        for_each_process(tsk) {
 112                struct task_struct *p;
 113                short oom_score_adj;
 114
 115                if (tsk->flags & PF_KTHREAD)
 116                        continue;
 117
 118                p = find_lock_task_mm(tsk);
 119                if (!p)
 120                        continue;
 121
 122                if (test_tsk_thread_flag(p, TIF_MEMDIE) &&
 123                    time_before_eq(jiffies, lowmem_deathpending_timeout)) {
 124                        task_unlock(p);
 125                        rcu_read_unlock();
 126                        return 0;
 127                }
 128                oom_score_adj = p->signal->oom_score_adj;
 129                if (oom_score_adj < min_score_adj) {
 130                        task_unlock(p);
 131                        continue;
 132                }
 133                tasksize = get_mm_rss(p->mm);
 134                task_unlock(p);
 135                if (tasksize <= 0)
 136                        continue;
 137                if (selected) {
 138                        if (oom_score_adj < selected_oom_score_adj)
 139                                continue;
 140                        if (oom_score_adj == selected_oom_score_adj &&
 141                            tasksize <= selected_tasksize)
 142                                continue;
 143                }
 144                selected = p;
 145                selected_tasksize = tasksize;
 146                selected_oom_score_adj = oom_score_adj;
 147                lowmem_print(2, "select %d (%s), adj %hd, size %d, to kill\n",
 148                             p->pid, p->comm, oom_score_adj, tasksize);
 149        }
 150        if (selected) {
 151                lowmem_print(1, "send sigkill to %d (%s), adj %hd, size %d\n",
 152                             selected->pid, selected->comm,
 153                             selected_oom_score_adj, selected_tasksize);
 154                lowmem_deathpending_timeout = jiffies + HZ;
 155                send_sig(SIGKILL, selected, 0);
 156                set_tsk_thread_flag(selected, TIF_MEMDIE);
 157                rem -= selected_tasksize;
 158        }
 159        lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
 160                     sc->nr_to_scan, sc->gfp_mask, rem);
 161        rcu_read_unlock();
 162        return rem;
 163}
 164
 165static struct shrinker lowmem_shrinker = {
 166        .shrink = lowmem_shrink,
 167        .seeks = DEFAULT_SEEKS * 16
 168};
 169
 170static int __init lowmem_init(void)
 171{
 172        register_shrinker(&lowmem_shrinker);
 173        return 0;
 174}
 175
 176static void __exit lowmem_exit(void)
 177{
 178        unregister_shrinker(&lowmem_shrinker);
 179}
 180
 181module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);
 182module_param_array_named(adj, lowmem_adj, short, &lowmem_adj_size,
 183                         S_IRUGO | S_IWUSR);
 184module_param_array_named(minfree, lowmem_minfree, uint, &lowmem_minfree_size,
 185                         S_IRUGO | S_IWUSR);
 186module_param_named(debug_level, lowmem_debug_level, uint, S_IRUGO | S_IWUSR);
 187
 188module_init(lowmem_init);
 189module_exit(lowmem_exit);
 190
 191MODULE_LICENSE("GPL");
 192
 193