diff options
Diffstat (limited to 'mm/memcontrol.c')
-rw-r--r-- | mm/memcontrol.c | 69 |
1 files changed, 69 insertions, 0 deletions
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 | */ | ||
734 | void 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); | ||
780 | done: | ||
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. |