summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBalbir Singh <balbir@linux.vnet.ibm.com>2009-04-02 19:57:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-02 22:04:55 -0400
commite222432bfa7dcf6ec008622a978c9f284ed5e3a9 (patch)
treeb006f569cb66523a5644ad0ef1669b051ccda907
parent0b7f569e45bb6be142d87017030669a6a7d327a1 (diff)
memcg: show memcg information during OOM
Add RSS and swap to OOM output from memcg Display memcg values like failcnt, usage and limit when an OOM occurs due to memcg. Thanks to Johannes Weiner, Li Zefan, David Rientjes, Kamezawa Hiroyuki, Daisuke Nishimura and KOSAKI Motohiro for review. Sample output ------------- Task in /a/x killed as a result of limit of /a memory: usage 1048576kB, limit 1048576kB, failcnt 4183 memory+swap: usage 1400964kB, limit 9007199254740991kB, failcnt 0 [akpm@linux-foundation.org: compilation fix] [akpm@linux-foundation.org: fix kerneldoc and whitespace] [akpm@linux-foundation.org: add printk facility level] Signed-off-by: Balbir Singh <balbir@linux.vnet.ibm.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Paul Menage <menage@google.com> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/memcontrol.h7
-rw-r--r--mm/memcontrol.c69
-rw-r--r--mm/oom_kill.c1
3 files changed, 77 insertions, 0 deletions
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 326f45c86530..7aba9f264622 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -104,6 +104,8 @@ struct zone_reclaim_stat *mem_cgroup_get_reclaim_stat(struct mem_cgroup *memcg,
104 struct zone *zone); 104 struct zone *zone);
105struct zone_reclaim_stat* 105struct zone_reclaim_stat*
106mem_cgroup_get_reclaim_stat_from_page(struct page *page); 106mem_cgroup_get_reclaim_stat_from_page(struct page *page);
107extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg,
108 struct task_struct *p);
107 109
108#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP 110#ifdef CONFIG_CGROUP_MEM_RES_CTLR_SWAP
109extern int do_swap_account; 111extern int do_swap_account;
@@ -270,6 +272,11 @@ mem_cgroup_get_reclaim_stat_from_page(struct page *page)
270 return NULL; 272 return NULL;
271} 273}
272 274
275static inline void
276mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
277{
278}
279
273#endif /* CONFIG_CGROUP_MEM_CONT */ 280#endif /* CONFIG_CGROUP_MEM_CONT */
274 281
275#endif /* _LINUX_MEMCONTROL_H */ 282#endif /* _LINUX_MEMCONTROL_H */
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 025f8abfae2d..2bdb6149faeb 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -27,6 +27,7 @@
27#include <linux/backing-dev.h> 27#include <linux/backing-dev.h>
28#include <linux/bit_spinlock.h> 28#include <linux/bit_spinlock.h>
29#include <linux/rcupdate.h> 29#include <linux/rcupdate.h>
30#include <linux/limits.h>
30#include <linux/mutex.h> 31#include <linux/mutex.h>
31#include <linux/slab.h> 32#include <linux/slab.h>
32#include <linux/swap.h> 33#include <linux/swap.h>
@@ -721,6 +722,74 @@ static int mem_cgroup_count_children_cb(struct mem_cgroup *mem, void *data)
721 (*val)++; 722 (*val)++;
722 return 0; 723 return 0;
723} 724}
725
726/**
727 * mem_cgroup_print_mem_info: Called from OOM with tasklist_lock held in read mode.
728 * @memcg: The memory cgroup that went over limit
729 * @p: Task that is going to be killed
730 *
731 * NOTE: @memcg and @p's mem_cgroup can be different when hierarchy is
732 * enabled
733 */
734void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
735{
736 struct cgroup *task_cgrp;
737 struct cgroup *mem_cgrp;
738 /*
739 * Need a buffer in BSS, can't rely on allocations. The code relies
740 * on the assumption that OOM is serialized for memory controller.
741 * If this assumption is broken, revisit this code.
742 */
743 static char memcg_name[PATH_MAX];
744 int ret;
745
746 if (!memcg)
747 return;
748
749
750 rcu_read_lock();
751
752 mem_cgrp = memcg->css.cgroup;
753 task_cgrp = task_cgroup(p, mem_cgroup_subsys_id);
754
755 ret = cgroup_path(task_cgrp, memcg_name, PATH_MAX);
756 if (ret < 0) {
757 /*
758 * Unfortunately, we are unable to convert to a useful name
759 * But we'll still print out the usage information
760 */
761 rcu_read_unlock();
762 goto done;
763 }
764 rcu_read_unlock();
765
766 printk(KERN_INFO "Task in %s killed", memcg_name);
767
768 rcu_read_lock();
769 ret = cgroup_path(mem_cgrp, memcg_name, PATH_MAX);
770 if (ret < 0) {
771 rcu_read_unlock();
772 goto done;
773 }
774 rcu_read_unlock();
775
776 /*
777 * Continues from above, so we don't need an KERN_ level
778 */
779 printk(KERN_CONT " as a result of limit of %s\n", memcg_name);
780done:
781
782 printk(KERN_INFO "memory: usage %llukB, limit %llukB, failcnt %llu\n",
783 res_counter_read_u64(&memcg->res, RES_USAGE) >> 10,
784 res_counter_read_u64(&memcg->res, RES_LIMIT) >> 10,
785 res_counter_read_u64(&memcg->res, RES_FAILCNT));
786 printk(KERN_INFO "memory+swap: usage %llukB, limit %llukB, "
787 "failcnt %llu\n",
788 res_counter_read_u64(&memcg->memsw, RES_USAGE) >> 10,
789 res_counter_read_u64(&memcg->memsw, RES_LIMIT) >> 10,
790 res_counter_read_u64(&memcg->memsw, RES_FAILCNT));
791}
792
724/* 793/*
725 * This function returns the number of memcg under hierarchy tree. Returns 794 * This function returns the number of memcg under hierarchy tree. Returns
726 * 1(self count) if no children. 795 * 1(self count) if no children.
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index d3b9bac085b5..2f3166e308d9 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -394,6 +394,7 @@ static int oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
394 cpuset_print_task_mems_allowed(current); 394 cpuset_print_task_mems_allowed(current);
395 task_unlock(current); 395 task_unlock(current);
396 dump_stack(); 396 dump_stack();
397 mem_cgroup_print_oom_info(mem, current);
397 show_mem(); 398 show_mem();
398 if (sysctl_oom_dump_tasks) 399 if (sysctl_oom_dump_tasks)
399 dump_tasks(mem); 400 dump_tasks(mem);