diff options
| -rw-r--r-- | drivers/char/sysrq.c | 2 | ||||
| -rw-r--r-- | include/linux/swap.h | 2 | ||||
| -rw-r--r-- | mm/oom_kill.c | 103 | ||||
| -rw-r--r-- | mm/page_alloc.c | 2 |
4 files changed, 81 insertions, 28 deletions
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 5765f672e853..d58f82318853 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c | |||
| @@ -243,7 +243,7 @@ static struct sysrq_key_op sysrq_term_op = { | |||
| 243 | 243 | ||
| 244 | static void moom_callback(void *ignored) | 244 | static void moom_callback(void *ignored) |
| 245 | { | 245 | { |
| 246 | out_of_memory(GFP_KERNEL, 0); | 246 | out_of_memory(&NODE_DATA(0)->node_zonelists[ZONE_NORMAL], GFP_KERNEL, 0); |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | static DECLARE_WORK(moom_work, moom_callback, NULL); | 249 | static DECLARE_WORK(moom_work, moom_callback, NULL); |
diff --git a/include/linux/swap.h b/include/linux/swap.h index f3e17d5963c3..d572b19afb7d 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h | |||
| @@ -147,7 +147,7 @@ struct swap_list_t { | |||
| 147 | #define vm_swap_full() (nr_swap_pages*2 < total_swap_pages) | 147 | #define vm_swap_full() (nr_swap_pages*2 < total_swap_pages) |
| 148 | 148 | ||
| 149 | /* linux/mm/oom_kill.c */ | 149 | /* linux/mm/oom_kill.c */ |
| 150 | extern void out_of_memory(gfp_t gfp_mask, int order); | 150 | extern void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order); |
| 151 | 151 | ||
| 152 | /* linux/mm/memory.c */ | 152 | /* linux/mm/memory.c */ |
| 153 | extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *); | 153 | extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *); |
diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 949eba1d5ba3..8123fad5a485 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c | |||
| @@ -133,6 +133,36 @@ unsigned long badness(struct task_struct *p, unsigned long uptime) | |||
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | /* | 135 | /* |
| 136 | * Types of limitations to the nodes from which allocations may occur | ||
| 137 | */ | ||
| 138 | #define CONSTRAINT_NONE 1 | ||
| 139 | #define CONSTRAINT_MEMORY_POLICY 2 | ||
| 140 | #define CONSTRAINT_CPUSET 3 | ||
| 141 | |||
| 142 | /* | ||
| 143 | * Determine the type of allocation constraint. | ||
| 144 | */ | ||
| 145 | static inline int constrained_alloc(struct zonelist *zonelist, gfp_t gfp_mask) | ||
| 146 | { | ||
| 147 | #ifdef CONFIG_NUMA | ||
| 148 | struct zone **z; | ||
| 149 | nodemask_t nodes = node_online_map; | ||
| 150 | |||
| 151 | for (z = zonelist->zones; *z; z++) | ||
| 152 | if (cpuset_zone_allowed(*z, gfp_mask)) | ||
| 153 | node_clear((*z)->zone_pgdat->node_id, | ||
| 154 | nodes); | ||
| 155 | else | ||
| 156 | return CONSTRAINT_CPUSET; | ||
| 157 | |||
| 158 | if (!nodes_empty(nodes)) | ||
| 159 | return CONSTRAINT_MEMORY_POLICY; | ||
| 160 | #endif | ||
| 161 | |||
| 162 | return CONSTRAINT_NONE; | ||
| 163 | } | ||
| 164 | |||
| 165 | /* | ||
| 136 | * Simple selection loop. We chose the process with the highest | 166 | * Simple selection loop. We chose the process with the highest |
| 137 | * number of 'points'. We expect the caller will lock the tasklist. | 167 | * number of 'points'. We expect the caller will lock the tasklist. |
| 138 | * | 168 | * |
| @@ -184,7 +214,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints) | |||
| 184 | * CAP_SYS_RAW_IO set, send SIGTERM instead (but it's unlikely that | 214 | * CAP_SYS_RAW_IO set, send SIGTERM instead (but it's unlikely that |
| 185 | * we select a process with CAP_SYS_RAW_IO set). | 215 | * we select a process with CAP_SYS_RAW_IO set). |
| 186 | */ | 216 | */ |
| 187 | static void __oom_kill_task(task_t *p) | 217 | static void __oom_kill_task(task_t *p, const char *message) |
| 188 | { | 218 | { |
| 189 | if (p->pid == 1) { | 219 | if (p->pid == 1) { |
| 190 | WARN_ON(1); | 220 | WARN_ON(1); |
| @@ -200,8 +230,8 @@ static void __oom_kill_task(task_t *p) | |||
| 200 | return; | 230 | return; |
| 201 | } | 231 | } |
| 202 | task_unlock(p); | 232 | task_unlock(p); |
| 203 | printk(KERN_ERR "Out of Memory: Killed process %d (%s).\n", | 233 | printk(KERN_ERR "%s: Killed process %d (%s).\n", |
| 204 | p->pid, p->comm); | 234 | message, p->pid, p->comm); |
| 205 | 235 | ||
| 206 | /* | 236 | /* |
| 207 | * We give our sacrificial lamb high priority and access to | 237 | * We give our sacrificial lamb high priority and access to |
| @@ -214,7 +244,7 @@ static void __oom_kill_task(task_t *p) | |||
| 214 | force_sig(SIGKILL, p); | 244 | force_sig(SIGKILL, p); |
| 215 | } | 245 | } |
| 216 | 246 | ||
| 217 | static struct mm_struct *oom_kill_task(task_t *p) | 247 | static struct mm_struct *oom_kill_task(task_t *p, const char *message) |
| 218 | { | 248 | { |
| 219 | struct mm_struct *mm = get_task_mm(p); | 249 | struct mm_struct *mm = get_task_mm(p); |
| 220 | task_t * g, * q; | 250 | task_t * g, * q; |
| @@ -226,21 +256,21 @@ static struct mm_struct *oom_kill_task(task_t *p) | |||
| 226 | return NULL; | 256 | return NULL; |
| 227 | } | 257 | } |
| 228 | 258 | ||
| 229 | __oom_kill_task(p); | 259 | __oom_kill_task(p, message); |
| 230 | /* | 260 | /* |
| 231 | * kill all processes that share the ->mm (i.e. all threads), | 261 | * kill all processes that share the ->mm (i.e. all threads), |
| 232 | * but are in a different thread group | 262 | * but are in a different thread group |
| 233 | */ | 263 | */ |
| 234 | do_each_thread(g, q) | 264 | do_each_thread(g, q) |
| 235 | if (q->mm == mm && q->tgid != p->tgid) | 265 | if (q->mm == mm && q->tgid != p->tgid) |
| 236 | __oom_kill_task(q); | 266 | __oom_kill_task(q, message); |
| 237 | while_each_thread(g, q); | 267 | while_each_thread(g, q); |
| 238 | 268 | ||
| 239 | return mm; | 269 | return mm; |
| 240 | } | 270 | } |
| 241 | 271 | ||
| 242 | static struct mm_struct *oom_kill_process(struct task_struct *p, | 272 | static struct mm_struct *oom_kill_process(struct task_struct *p, |
| 243 | unsigned long points) | 273 | unsigned long points, const char *message) |
| 244 | { | 274 | { |
| 245 | struct mm_struct *mm; | 275 | struct mm_struct *mm; |
| 246 | struct task_struct *c; | 276 | struct task_struct *c; |
| @@ -253,11 +283,11 @@ static struct mm_struct *oom_kill_process(struct task_struct *p, | |||
| 253 | c = list_entry(tsk, struct task_struct, sibling); | 283 | c = list_entry(tsk, struct task_struct, sibling); |
| 254 | if (c->mm == p->mm) | 284 | if (c->mm == p->mm) |
| 255 | continue; | 285 | continue; |
| 256 | mm = oom_kill_task(c); | 286 | mm = oom_kill_task(c, message); |
| 257 | if (mm) | 287 | if (mm) |
| 258 | return mm; | 288 | return mm; |
| 259 | } | 289 | } |
| 260 | return oom_kill_task(p); | 290 | return oom_kill_task(p, message); |
| 261 | } | 291 | } |
| 262 | 292 | ||
| 263 | /** | 293 | /** |
| @@ -268,10 +298,10 @@ static struct mm_struct *oom_kill_process(struct task_struct *p, | |||
| 268 | * OR try to be smart about which process to kill. Note that we | 298 | * OR try to be smart about which process to kill. Note that we |
| 269 | * don't have to be perfect here, we just have to be good. | 299 | * don't have to be perfect here, we just have to be good. |
| 270 | */ | 300 | */ |
| 271 | void out_of_memory(gfp_t gfp_mask, int order) | 301 | void out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, int order) |
| 272 | { | 302 | { |
| 273 | struct mm_struct *mm = NULL; | 303 | struct mm_struct *mm = NULL; |
| 274 | task_t * p; | 304 | task_t *p; |
| 275 | unsigned long points; | 305 | unsigned long points; |
| 276 | 306 | ||
| 277 | if (printk_ratelimit()) { | 307 | if (printk_ratelimit()) { |
| @@ -283,25 +313,48 @@ void out_of_memory(gfp_t gfp_mask, int order) | |||
| 283 | 313 | ||
| 284 | cpuset_lock(); | 314 | cpuset_lock(); |
| 285 | read_lock(&tasklist_lock); | 315 | read_lock(&tasklist_lock); |
| 316 | |||
| 317 | /* | ||
| 318 | * Check if there were limitations on the allocation (only relevant for | ||
| 319 | * NUMA) that may require different handling. | ||
| 320 | */ | ||
| 321 | switch (constrained_alloc(zonelist, gfp_mask)) { | ||
| 322 | case CONSTRAINT_MEMORY_POLICY: | ||
| 323 | mm = oom_kill_process(current, points, | ||
| 324 | "No available memory (MPOL_BIND)"); | ||
| 325 | break; | ||
| 326 | |||
| 327 | case CONSTRAINT_CPUSET: | ||
| 328 | mm = oom_kill_process(current, points, | ||
| 329 | "No available memory in cpuset"); | ||
| 330 | break; | ||
| 331 | |||
| 332 | case CONSTRAINT_NONE: | ||
| 286 | retry: | 333 | retry: |
| 287 | p = select_bad_process(&points); | 334 | /* |
| 335 | * Rambo mode: Shoot down a process and hope it solves whatever | ||
| 336 | * issues we may have. | ||
| 337 | */ | ||
| 338 | p = select_bad_process(&points); | ||
| 288 | 339 | ||
| 289 | if (PTR_ERR(p) == -1UL) | 340 | if (PTR_ERR(p) == -1UL) |
| 290 | goto out; | 341 | goto out; |
| 291 | 342 | ||
| 292 | /* Found nothing?!?! Either we hang forever, or we panic. */ | 343 | /* Found nothing?!?! Either we hang forever, or we panic. */ |
| 293 | if (!p) { | 344 | if (!p) { |
| 294 | read_unlock(&tasklist_lock); | 345 | read_unlock(&tasklist_lock); |
| 295 | cpuset_unlock(); | 346 | cpuset_unlock(); |
| 296 | panic("Out of memory and no killable processes...\n"); | 347 | panic("Out of memory and no killable processes...\n"); |
| 297 | } | 348 | } |
| 298 | 349 | ||
| 299 | mm = oom_kill_process(p, points); | 350 | mm = oom_kill_process(p, points, "Out of memory"); |
| 300 | if (!mm) | 351 | if (!mm) |
| 301 | goto retry; | 352 | goto retry; |
| 353 | |||
| 354 | break; | ||
| 355 | } | ||
| 302 | 356 | ||
| 303 | out: | 357 | out: |
| 304 | read_unlock(&tasklist_lock); | ||
| 305 | cpuset_unlock(); | 358 | cpuset_unlock(); |
| 306 | if (mm) | 359 | if (mm) |
| 307 | mmput(mm); | 360 | mmput(mm); |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 208812b25597..791690d7d3fa 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -1015,7 +1015,7 @@ rebalance: | |||
| 1015 | if (page) | 1015 | if (page) |
| 1016 | goto got_pg; | 1016 | goto got_pg; |
| 1017 | 1017 | ||
| 1018 | out_of_memory(gfp_mask, order); | 1018 | out_of_memory(zonelist, gfp_mask, order); |
| 1019 | goto restart; | 1019 | goto restart; |
| 1020 | } | 1020 | } |
| 1021 | 1021 | ||
