From f99efe3f04efa0fb05dcc2d0ad2d987d60ee6c12 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Mon, 31 Oct 2011 17:07:18 -0700 Subject: [PATCH] --- yaml --- r: 272118 b: refs/heads/master c: 43362a4977e37db46f86f7e6ab935f0006956632 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/include/linux/oom.h | 1 + trunk/mm/ksm.c | 3 ++- trunk/mm/oom_kill.c | 19 +++++++++++++++++++ trunk/mm/swapfile.c | 2 +- 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/[refs] b/[refs] index 74e6723f0b8f..c496720262c9 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: c9f01245b6a7d77d17deaa71af10f6aca14fa24e +refs/heads/master: 43362a4977e37db46f86f7e6ab935f0006956632 diff --git a/trunk/include/linux/oom.h b/trunk/include/linux/oom.h index 13b7b02e599a..6f9d04a85336 100644 --- a/trunk/include/linux/oom.h +++ b/trunk/include/linux/oom.h @@ -40,6 +40,7 @@ enum oom_constraint { CONSTRAINT_MEMCG, }; +extern void compare_swap_oom_score_adj(int old_val, int new_val); extern int test_set_oom_score_adj(int new_val); extern unsigned int oom_badness(struct task_struct *p, struct mem_cgroup *mem, diff --git a/trunk/mm/ksm.c b/trunk/mm/ksm.c index 9a68b0cf0a1c..310544a379ae 100644 --- a/trunk/mm/ksm.c +++ b/trunk/mm/ksm.c @@ -1905,7 +1905,8 @@ static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr, oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX); err = unmerge_and_remove_all_rmap_items(); - test_set_oom_score_adj(oom_score_adj); + compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, + oom_score_adj); if (err) { ksm_run = KSM_RUN_STOP; count = err; diff --git a/trunk/mm/oom_kill.c b/trunk/mm/oom_kill.c index 2b97e8f04607..e916168b6e0a 100644 --- a/trunk/mm/oom_kill.c +++ b/trunk/mm/oom_kill.c @@ -39,6 +39,25 @@ int sysctl_oom_kill_allocating_task; int sysctl_oom_dump_tasks = 1; static DEFINE_SPINLOCK(zone_scan_lock); +/* + * compare_swap_oom_score_adj() - compare and swap current's oom_score_adj + * @old_val: old oom_score_adj for compare + * @new_val: new oom_score_adj for swap + * + * Sets the oom_score_adj value for current to @new_val iff its present value is + * @old_val. Usually used to reinstate a previous value to prevent racing with + * userspacing tuning the value in the interim. + */ +void compare_swap_oom_score_adj(int old_val, int new_val) +{ + struct sighand_struct *sighand = current->sighand; + + spin_lock_irq(&sighand->siglock); + if (current->signal->oom_score_adj == old_val) + current->signal->oom_score_adj = new_val; + spin_unlock_irq(&sighand->siglock); +} + /** * test_set_oom_score_adj() - set current's oom_score_adj and return old value * @new_val: new oom_score_adj value diff --git a/trunk/mm/swapfile.c b/trunk/mm/swapfile.c index 17bc224bce68..c9d654009125 100644 --- a/trunk/mm/swapfile.c +++ b/trunk/mm/swapfile.c @@ -1617,7 +1617,7 @@ SYSCALL_DEFINE1(swapoff, const char __user *, specialfile) oom_score_adj = test_set_oom_score_adj(OOM_SCORE_ADJ_MAX); err = try_to_unuse(type); - test_set_oom_score_adj(oom_score_adj); + compare_swap_oom_score_adj(OOM_SCORE_ADJ_MAX, oom_score_adj); if (err) { /*