aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/oom.h19
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/linux/types.h1
-rw-r--r--mm/ksm.c7
-rw-r--r--mm/oom_kill.c49
-rw-r--r--mm/swapfile.c5
6 files changed, 30 insertions, 52 deletions
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 922dab164eb0..da60007075b5 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -29,8 +29,23 @@ enum oom_scan_t {
29 OOM_SCAN_SELECT, /* always select this thread first */ 29 OOM_SCAN_SELECT, /* always select this thread first */
30}; 30};
31 31
32extern void compare_swap_oom_score_adj(short old_val, short new_val); 32/* Thread is the potential origin of an oom condition; kill first on oom */
33extern short test_set_oom_score_adj(short new_val); 33#define OOM_FLAG_ORIGIN ((__force oom_flags_t)0x1)
34
35static inline void set_current_oom_origin(void)
36{
37 current->signal->oom_flags |= OOM_FLAG_ORIGIN;
38}
39
40static inline void clear_current_oom_origin(void)
41{
42 current->signal->oom_flags &= ~OOM_FLAG_ORIGIN;
43}
44
45static inline bool oom_task_origin(const struct task_struct *p)
46{
47 return !!(p->signal->oom_flags & OOM_FLAG_ORIGIN);
48}
34 49
35extern unsigned long oom_badness(struct task_struct *p, 50extern unsigned long oom_badness(struct task_struct *p,
36 struct mem_cgroup *memcg, const nodemask_t *nodemask, 51 struct mem_cgroup *memcg, const nodemask_t *nodemask,
diff --git a/include/linux/sched.h b/include/linux/sched.h
index ed30456152da..3e387df065fc 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -631,6 +631,7 @@ struct signal_struct {
631 struct rw_semaphore group_rwsem; 631 struct rw_semaphore group_rwsem;
632#endif 632#endif
633 633
634 oom_flags_t oom_flags;
634 short oom_score_adj; /* OOM kill score adjustment */ 635 short oom_score_adj; /* OOM kill score adjustment */
635 short oom_score_adj_min; /* OOM kill score adjustment min value. 636 short oom_score_adj_min; /* OOM kill score adjustment min value.
636 * Only settable by CAP_SYS_RESOURCE. */ 637 * Only settable by CAP_SYS_RESOURCE. */
diff --git a/include/linux/types.h b/include/linux/types.h
index 1cc0e4b9a048..4d118ba11349 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -156,6 +156,7 @@ typedef u32 dma_addr_t;
156#endif 156#endif
157typedef unsigned __bitwise__ gfp_t; 157typedef unsigned __bitwise__ gfp_t;
158typedef unsigned __bitwise__ fmode_t; 158typedef unsigned __bitwise__ fmode_t;
159typedef unsigned __bitwise__ oom_flags_t;
159 160
160#ifdef CONFIG_PHYS_ADDR_T_64BIT 161#ifdef CONFIG_PHYS_ADDR_T_64BIT
161typedef u64 phys_addr_t; 162typedef u64 phys_addr_t;
diff --git a/mm/ksm.c b/mm/ksm.c
index b4d5a9deb17f..382d930a0bf1 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -1919,12 +1919,9 @@ static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr,
1919 if (ksm_run != flags) { 1919 if (ksm_run != flags) {
1920 ksm_run = flags; 1920 ksm_run = flags;
1921 if (flags & KSM_RUN_UNMERGE) { 1921 if (flags & KSM_RUN_UNMERGE) {
1922 short oom_score_adj; 1922 set_current_oom_origin();
1923
1924 oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX);
1925 err = unmerge_and_remove_all_rmap_items(); 1923 err = unmerge_and_remove_all_rmap_items();
1926 compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, 1924 clear_current_oom_origin();
1927 oom_score_adj);
1928 if (err) { 1925 if (err) {
1929 ksm_run = KSM_RUN_STOP; 1926 ksm_run = KSM_RUN_STOP;
1930 count = err; 1927 count = err;
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 37ab4c5ab6e8..18f1ae2b45de 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -44,48 +44,6 @@ int sysctl_oom_kill_allocating_task;
44int sysctl_oom_dump_tasks = 1; 44int sysctl_oom_dump_tasks = 1;
45static DEFINE_SPINLOCK(zone_scan_lock); 45static DEFINE_SPINLOCK(zone_scan_lock);
46 46
47/*
48 * compare_swap_oom_score_adj() - compare and swap current's oom_score_adj
49 * @old_val: old oom_score_adj for compare
50 * @new_val: new oom_score_adj for swap
51 *
52 * Sets the oom_score_adj value for current to @new_val iff its present value is
53 * @old_val. Usually used to reinstate a previous value to prevent racing with
54 * userspacing tuning the value in the interim.
55 */
56void compare_swap_oom_score_adj(short old_val, short new_val)
57{
58 struct sighand_struct *sighand = current->sighand;
59
60 spin_lock_irq(&sighand->siglock);
61 if (current->signal->oom_score_adj == old_val)
62 current->signal->oom_score_adj = new_val;
63 trace_oom_score_adj_update(current);
64 spin_unlock_irq(&sighand->siglock);
65}
66
67/**
68 * test_set_oom_score_adj() - set current's oom_score_adj and return old value
69 * @new_val: new oom_score_adj value
70 *
71 * Sets the oom_score_adj value for current to @new_val with proper
72 * synchronization and returns the old value. Usually used to temporarily
73 * set a value, save the old value in the caller, and then reinstate it later.
74 */
75short test_set_oom_score_adj(short new_val)
76{
77 struct sighand_struct *sighand = current->sighand;
78 int old_val;
79
80 spin_lock_irq(&sighand->siglock);
81 old_val = current->signal->oom_score_adj;
82 current->signal->oom_score_adj = new_val;
83 trace_oom_score_adj_update(current);
84 spin_unlock_irq(&sighand->siglock);
85
86 return old_val;
87}
88
89#ifdef CONFIG_NUMA 47#ifdef CONFIG_NUMA
90/** 48/**
91 * has_intersects_mems_allowed() - check task eligiblity for kill 49 * has_intersects_mems_allowed() - check task eligiblity for kill
@@ -310,6 +268,13 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task,
310 if (!task->mm) 268 if (!task->mm)
311 return OOM_SCAN_CONTINUE; 269 return OOM_SCAN_CONTINUE;
312 270
271 /*
272 * If task is allocating a lot of memory and has been marked to be
273 * killed first if it triggers an oom, then select it.
274 */
275 if (oom_task_origin(task))
276 return OOM_SCAN_SELECT;
277
313 if (task->flags & PF_EXITING && !force_kill) { 278 if (task->flags & PF_EXITING && !force_kill) {
314 /* 279 /*
315 * If this task is not being ptraced on exit, then wait for it 280 * If this task is not being ptraced on exit, then wait for it
diff --git a/mm/swapfile.c b/mm/swapfile.c
index bb6f6a04e92d..e97a0e5aea91 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1498,7 +1498,6 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
1498 struct address_space *mapping; 1498 struct address_space *mapping;
1499 struct inode *inode; 1499 struct inode *inode;
1500 struct filename *pathname; 1500 struct filename *pathname;
1501 short oom_score_adj;
1502 int i, type, prev; 1501 int i, type, prev;
1503 int err; 1502 int err;
1504 1503
@@ -1557,9 +1556,9 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile)
1557 p->flags &= ~SWP_WRITEOK; 1556 p->flags &= ~SWP_WRITEOK;
1558 spin_unlock(&swap_lock); 1557 spin_unlock(&swap_lock);
1559 1558
1560 oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX); 1559 set_current_oom_origin();
1561 err = try_to_unuse(type, false, 0); /* force all pages to be unused */ 1560 err = try_to_unuse(type, false, 0); /* force all pages to be unused */
1562 compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, oom_score_adj); 1561 clear_current_oom_origin();
1563 1562
1564 if (err) { 1563 if (err) {
1565 /* re-insert swap space back into swap_list */ 1564 /* re-insert swap space back into swap_list */