diff options
-rw-r--r-- | include/linux/oom.h | 19 | ||||
-rw-r--r-- | include/linux/sched.h | 1 | ||||
-rw-r--r-- | include/linux/types.h | 1 | ||||
-rw-r--r-- | mm/ksm.c | 7 | ||||
-rw-r--r-- | mm/oom_kill.c | 49 | ||||
-rw-r--r-- | mm/swapfile.c | 5 |
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 | ||
32 | extern 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 */ |
33 | extern short test_set_oom_score_adj(short new_val); | 33 | #define OOM_FLAG_ORIGIN ((__force oom_flags_t)0x1) |
34 | |||
35 | static inline void set_current_oom_origin(void) | ||
36 | { | ||
37 | current->signal->oom_flags |= OOM_FLAG_ORIGIN; | ||
38 | } | ||
39 | |||
40 | static inline void clear_current_oom_origin(void) | ||
41 | { | ||
42 | current->signal->oom_flags &= ~OOM_FLAG_ORIGIN; | ||
43 | } | ||
44 | |||
45 | static inline bool oom_task_origin(const struct task_struct *p) | ||
46 | { | ||
47 | return !!(p->signal->oom_flags & OOM_FLAG_ORIGIN); | ||
48 | } | ||
34 | 49 | ||
35 | extern unsigned long oom_badness(struct task_struct *p, | 50 | extern 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 |
157 | typedef unsigned __bitwise__ gfp_t; | 157 | typedef unsigned __bitwise__ gfp_t; |
158 | typedef unsigned __bitwise__ fmode_t; | 158 | typedef unsigned __bitwise__ fmode_t; |
159 | typedef unsigned __bitwise__ oom_flags_t; | ||
159 | 160 | ||
160 | #ifdef CONFIG_PHYS_ADDR_T_64BIT | 161 | #ifdef CONFIG_PHYS_ADDR_T_64BIT |
161 | typedef u64 phys_addr_t; | 162 | typedef u64 phys_addr_t; |
@@ -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; | |||
44 | int sysctl_oom_dump_tasks = 1; | 44 | int sysctl_oom_dump_tasks = 1; |
45 | static DEFINE_SPINLOCK(zone_scan_lock); | 45 | static 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 | */ | ||
56 | void 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 | */ | ||
75 | short 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 */ |