Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

android, lowmemorykiller: remove task handoff notifier

The task handoff notifier leaks task_struct since it never gets freed
after the callback returns NOTIFY_OK, which means it is responsible for
doing so.

It turns out the lowmemorykiller actually doesn't need this notifier at
all. It's used to prevent unnecessary killing by waiting for a thread
to exit as a result of lowmem_shrink(), however, it's possible to do
this in the same way the kernel oom killer works by setting TIF_MEMDIE
and avoid killing if we're still waiting for it to exit.

The kernel oom killer will already automatically set TIF_MEMDIE for
threads that are attempting to allocate memory that have a fatal signal.
The thread selected by lowmem_shrink() will have such a signal after the
lowmemorykiller sends it a SIGKILL, so this won't result in an
unnecessary use of memory reserves for the thread to exit.

This has the added benefit that we don't have to rely on
CONFIG_PROFILING to prevent needlessly killing tasks.

Reported-by: Werner Landgraf <w.landgraf@ru.ru>
Cc: stable@vger.kernel.org
Signed-off-by: David Rientjes <rientjes@google.com>
Acked-by: Colin Cross <ccross@android.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

David Rientjes and committed by
Linus Torvalds
83dbbdbb 00341028

+7 -41
+7 -41
drivers/staging/android/lowmemorykiller.c
··· 55 55 }; 56 56 static int lowmem_minfree_size = 4; 57 57 58 - static struct task_struct *lowmem_deathpending; 59 58 static unsigned long lowmem_deathpending_timeout; 60 59 61 60 #define lowmem_print(level, x...) \ ··· 62 63 if (lowmem_debug_level >= (level)) \ 63 64 printk(x); \ 64 65 } while (0) 65 - 66 - static int 67 - task_notify_func(struct notifier_block *self, unsigned long val, void *data); 68 - 69 - static struct notifier_block task_nb = { 70 - .notifier_call = task_notify_func, 71 - }; 72 - 73 - static int 74 - task_notify_func(struct notifier_block *self, unsigned long val, void *data) 75 - { 76 - struct task_struct *task = data; 77 - 78 - if (task == lowmem_deathpending) 79 - lowmem_deathpending = NULL; 80 - 81 - return NOTIFY_OK; 82 - } 83 66 84 67 static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc) 85 68 { ··· 77 96 int other_free = global_page_state(NR_FREE_PAGES); 78 97 int other_file = global_page_state(NR_FILE_PAGES) - 79 98 global_page_state(NR_SHMEM); 80 - 81 - /* 82 - * If we already have a death outstanding, then 83 - * bail out right away; indicating to vmscan 84 - * that we have nothing further to offer on 85 - * this pass. 86 - * 87 - * Note: Currently you need CONFIG_PROFILING 88 - * for this to work correctly. 89 - */ 90 - if (lowmem_deathpending && 91 - time_before_eq(jiffies, lowmem_deathpending_timeout)) 92 - return 0; 93 99 94 100 if (lowmem_adj_size < array_size) 95 101 array_size = lowmem_adj_size; ··· 116 148 if (!p) 117 149 continue; 118 150 151 + if (test_tsk_thread_flag(p, TIF_MEMDIE) && 152 + time_before_eq(jiffies, lowmem_deathpending_timeout)) { 153 + task_unlock(p); 154 + rcu_read_unlock(); 155 + return 0; 156 + } 119 157 oom_score_adj = p->signal->oom_score_adj; 120 158 if (oom_score_adj < min_score_adj) { 121 159 task_unlock(p); ··· 148 174 lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n", 149 175 selected->pid, selected->comm, 150 176 selected_oom_score_adj, selected_tasksize); 151 - /* 152 - * If CONFIG_PROFILING is off, then we don't want to stall 153 - * the killer by setting lowmem_deathpending. 154 - */ 155 - #ifdef CONFIG_PROFILING 156 - lowmem_deathpending = selected; 157 177 lowmem_deathpending_timeout = jiffies + HZ; 158 - #endif 159 178 send_sig(SIGKILL, selected, 0); 179 + set_tsk_thread_flag(selected, TIF_MEMDIE); 160 180 rem -= selected_tasksize; 161 181 } 162 182 lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", ··· 166 198 167 199 static int __init lowmem_init(void) 168 200 { 169 - task_handoff_register(&task_nb); 170 201 register_shrinker(&lowmem_shrinker); 171 202 return 0; 172 203 } ··· 173 206 static void __exit lowmem_exit(void) 174 207 { 175 208 unregister_shrinker(&lowmem_shrinker); 176 - task_handoff_unregister(&task_nb); 177 209 } 178 210 179 211 module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);