diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 886e2224c5fd..659b0c58f13e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c | |||
@@ -153,7 +153,7 @@ struct mem_cgroup { | |||
153 | * Should the accounting and control be hierarchical, per subtree? | 153 | * Should the accounting and control be hierarchical, per subtree? |
154 | */ | 154 | */ |
155 | bool use_hierarchy; | 155 | bool use_hierarchy; |
156 | 156 | unsigned long last_oom_jiffies; | |
157 | int obsolete; | 157 | int obsolete; |
158 | atomic_t refcnt; | 158 | atomic_t refcnt; |
159 | /* | 159 | /* |
@@ -615,6 +615,22 @@ static int mem_cgroup_hierarchical_reclaim(struct mem_cgroup *root_mem, | |||
615 | return ret; | 615 | return ret; |
616 | } | 616 | } |
617 | 617 | ||
618 | bool mem_cgroup_oom_called(struct task_struct *task) | ||
619 | { | ||
620 | bool ret = false; | ||
621 | struct mem_cgroup *mem; | ||
622 | struct mm_struct *mm; | ||
623 | |||
624 | rcu_read_lock(); | ||
625 | mm = task->mm; | ||
626 | if (!mm) | ||
627 | mm = &init_mm; | ||
628 | mem = mem_cgroup_from_task(rcu_dereference(mm->owner)); | ||
629 | if (mem && time_before(jiffies, mem->last_oom_jiffies + HZ/10)) | ||
630 | ret = true; | ||
631 | rcu_read_unlock(); | ||
632 | return ret; | ||
633 | } | ||
618 | /* | 634 | /* |
619 | * Unlike exported interface, "oom" parameter is added. if oom==true, | 635 | * Unlike exported interface, "oom" parameter is added. if oom==true, |
620 | * oom-killer can be invoked. | 636 | * oom-killer can be invoked. |
@@ -626,6 +642,13 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
626 | struct mem_cgroup *mem, *mem_over_limit; | 642 | struct mem_cgroup *mem, *mem_over_limit; |
627 | int nr_retries = MEM_CGROUP_RECLAIM_RETRIES; | 643 | int nr_retries = MEM_CGROUP_RECLAIM_RETRIES; |
628 | struct res_counter *fail_res; | 644 | struct res_counter *fail_res; |
645 | |||
646 | if (unlikely(test_thread_flag(TIF_MEMDIE))) { | ||
647 | /* Don't account this! */ | ||
648 | *memcg = NULL; | ||
649 | return 0; | ||
650 | } | ||
651 | |||
629 | /* | 652 | /* |
630 | * We always charge the cgroup the mm_struct belongs to. | 653 | * We always charge the cgroup the mm_struct belongs to. |
631 | * The mm_struct's mem_cgroup changes on task migration if the | 654 | * The mm_struct's mem_cgroup changes on task migration if the |
@@ -694,8 +717,10 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm, | |||
694 | continue; | 717 | continue; |
695 | 718 | ||
696 | if (!nr_retries--) { | 719 | if (!nr_retries--) { |
697 | if (oom) | 720 | if (oom) { |
698 | mem_cgroup_out_of_memory(mem, gfp_mask); | 721 | mem_cgroup_out_of_memory(mem, gfp_mask); |
722 | mem->last_oom_jiffies = jiffies; | ||
723 | } | ||
699 | goto nomem; | 724 | goto nomem; |
700 | } | 725 | } |
701 | } | 726 | } |
@@ -832,7 +857,7 @@ static int mem_cgroup_move_parent(struct page_cgroup *pc, | |||
832 | 857 | ||
833 | 858 | ||
834 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false); | 859 | ret = __mem_cgroup_try_charge(NULL, gfp_mask, &parent, false); |
835 | if (ret) | 860 | if (ret || !parent) |
836 | return ret; | 861 | return ret; |
837 | 862 | ||
838 | if (!get_page_unless_zero(page)) | 863 | if (!get_page_unless_zero(page)) |
@@ -883,7 +908,7 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm, | |||
883 | 908 | ||
884 | mem = memcg; | 909 | mem = memcg; |
885 | ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, true); | 910 | ret = __mem_cgroup_try_charge(mm, gfp_mask, &mem, true); |
886 | if (ret) | 911 | if (ret || !mem) |
887 | return ret; | 912 | return ret; |
888 | 913 | ||
889 | __mem_cgroup_commit_charge(mem, pc, ctype); | 914 | __mem_cgroup_commit_charge(mem, pc, ctype); |