From 26251eaf98e26dc2ce2dc26d63bc502700760704 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Thu, 1 Oct 2009 15:44:08 -0700 Subject: [PATCH] memcg: fix refcnt going negative __mem_cgroup_largest_soft_limit_node() returns a mem_cgroup_per_zone "mz" with incremnted mz->mem->css's refcnt. Then, the caller of this function has to call css_put(mz->mem->css). But, mz can be !NULL even if "not found" i.e. without css_get(). By this, css->refcnt will go down to minus. This may cause various things...one of results will be initite-loop in css_tryget() as this. INFO: RCU detected CPU 0 stall (t=10000 jiffies) sending NMI to all CPUs: NMI backtrace for cpu 0 CPU 0: <> [] trace_hardirqs_off+0xd/0x10 [] flat_send_IPI_mask+0x90/0xb0 [] flat_send_IPI_all+0x69/0x70 [] arch_trigger_all_cpu_backtrace+0x62/0xa0 [] __rcu_pending+0x7e/0x370 [] rcu_check_callbacks+0x47/0x130 [] update_process_times+0x46/0x70 [] tick_sched_timer+0x60/0x160 [] ? tick_sched_timer+0x0/0x160 [] __run_hrtimer+0xba/0x150 [] hrtimer_interrupt+0xd5/0x1b0 [] ? trace_hardirqs_off_thunk+0x3a/0x3c [] smp_apic_timer_interrupt+0x6d/0x9b [] apic_timer_interrupt+0x13/0x20 [] ? mem_cgroup_walk_tree+0x156/0x180 [] ? mem_cgroup_walk_tree+0x73/0x180 [] ? mem_cgroup_walk_tree+0x32/0x180 [] ? mem_cgroup_get_local_stat+0x0/0x110 [] ? mem_control_stat_show+0x14b/0x330 [] ? cgroup_seqfile_show+0x3d/0x60 Above shows CPU0 caught in css_tryget()'s inifinite loop because of bad refcnt. This is a fix to set mz=NULL at the top of retry path. Signed-off-by: KAMEZAWA Hiroyuki Acked-by: Paul Menage Cc: Li Zefan Cc: Balbir Singh Cc: Daisuke Nishimura Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index e2b98a6875c..21a30629ca8 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -447,9 +447,10 @@ static struct mem_cgroup_per_zone * __mem_cgroup_largest_soft_limit_node(struct mem_cgroup_tree_per_zone *mctz) { struct rb_node *rightmost = NULL; - struct mem_cgroup_per_zone *mz = NULL; + struct mem_cgroup_per_zone *mz; retry: + mz = NULL; rightmost = rb_last(&mctz->rb_root); if (!rightmost) goto done; /* Nothing to reclaim from */