From patchwork Fri Dec 16 09:09:42 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Glauber Costa X-Patchwork-Id: 131796 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 5F6CA1007D4 for ; Fri, 16 Dec 2011 20:11:32 +1100 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760352Ab1LPJKw (ORCPT ); Fri, 16 Dec 2011 04:10:52 -0500 Received: from mailhub.sw.ru ([195.214.232.25]:8481 "EHLO relay.sw.ru" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760285Ab1LPJKs (ORCPT ); Fri, 16 Dec 2011 04:10:48 -0500 Received: from straightjacket.localdomain ([10.24.20.190]) by relay.sw.ru (8.13.4/8.13.4) with ESMTP id pBG9AFYH015505; Fri, 16 Dec 2011 12:10:17 +0300 (MSK) From: Glauber Costa To: davem@davemloft.net Cc: linux-kernel@vger.kernel.org, kamezawa.hiroyu@jp.fujitsu.com, netdev@vger.kernel.org, eric.dumazet@gmail.com, cgroups@vger.kernel.org, Glauber Costa , Stephen Rothwell , Randy Dunlap Subject: [PATCH v2] net: fix sleeping while atomic problem in sock mem_cgroup. Date: Fri, 16 Dec 2011 13:09:42 +0400 Message-Id: <1324026582-5214-1-git-send-email-glommer@parallels.com> X-Mailer: git-send-email 1.7.6.4 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Since we can't scan the proto_list to initialize sock cgroups, as it holds a rwlock, and we also want to keep the code generic enough to avoid calling the initialization functions of protocols directly, I propose we keep the interested parties in a separate list. This list is protected by a mutex so we can sleep and do the necessary allocations. Also fixes a reference problem found by Randy Dunlap's randconfig. Signed-off-by: Glauber Costa CC: Hiroyouki Kamezawa CC: David S. Miller CC: Eric Dumazet CC: Stephen Rothwell CC: Randy Dunlap --- include/linux/memcontrol.h | 11 ++++++- include/net/sock.h | 5 +--- include/net/tcp_memcontrol.h | 2 + mm/memcontrol.c | 58 ++++++++++++++++++++++++++++++++++++++++++ net/core/sock.c | 42 +++-------------------------- 5 files changed, 75 insertions(+), 43 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 9b296ea..e61fabb 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -390,11 +390,13 @@ enum { OVER_LIMIT, }; -#ifdef CONFIG_INET +struct proto; struct sock; #ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM void sock_update_memcg(struct sock *sk); void sock_release_memcg(struct sock *sk); +void register_sock_cgroup(struct proto *prot); +void unregister_sock_cgroup(struct proto *prot); #else static inline void sock_update_memcg(struct sock *sk) { @@ -402,7 +404,12 @@ static inline void sock_update_memcg(struct sock *sk) static inline void sock_release_memcg(struct sock *sk) { } +static inline void register_sock_cgroup(struct proto *prot) +{ +} +static inline void unregister_sock_cgroup(struct proto *prot) +{ +} #endif /* CONFIG_CGROUP_MEM_RES_CTLR_KMEM */ -#endif /* CONFIG_INET */ #endif /* _LINUX_MEMCONTROL_H */ diff --git a/include/net/sock.h b/include/net/sock.h index 6fe0dae..f8237a3 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -64,10 +64,6 @@ #include #include -struct cgroup; -struct cgroup_subsys; -int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss); -void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss); /* * This structure really needs to be cleaned up. * Most of it is for TCP, and not used by any of @@ -858,6 +854,7 @@ struct proto { void (*destroy_cgroup)(struct cgroup *cgrp, struct cgroup_subsys *ss); struct cg_proto *(*proto_cgroup)(struct mem_cgroup *memcg); + struct list_head cgroup_node; #endif }; diff --git a/include/net/tcp_memcontrol.h b/include/net/tcp_memcontrol.h index 3512082..5aa7c4b 100644 --- a/include/net/tcp_memcontrol.h +++ b/include/net/tcp_memcontrol.h @@ -11,6 +11,8 @@ struct tcp_memcontrol { int tcp_memory_pressure; }; +struct cgroup; +struct cgroup_subsys; struct cg_proto *tcp_proto_cgroup(struct mem_cgroup *memcg); int tcp_init_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss); void tcp_destroy_cgroup(struct cgroup *cgrp, struct cgroup_subsys *ss); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 7266202..1098afe 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4742,6 +4742,64 @@ static struct cftype kmem_cgroup_files[] = { }, }; +static DEFINE_MUTEX(cgroup_proto_list_lock); +static LIST_HEAD(cgroup_proto_list); + +static int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ + struct proto *proto; + int ret = 0; + + mutex_lock(&cgroup_proto_list_lock); + list_for_each_entry(proto, &cgroup_proto_list, cgroup_node) { + if (proto->init_cgroup) { + ret = proto->init_cgroup(cgrp, ss); + if (ret) + goto out; + } + } + + mutex_unlock(&cgroup_proto_list_lock); + return ret; +out: + list_for_each_entry_continue_reverse(proto, &cgroup_proto_list, cgroup_node) + if (proto->destroy_cgroup) + proto->destroy_cgroup(cgrp, ss); + mutex_unlock(&cgroup_proto_list_lock); + return ret; +} + +static void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss) +{ + struct proto *proto; + + mutex_lock(&cgroup_proto_list_lock); + list_for_each_entry_reverse(proto, &cgroup_proto_list, cgroup_node) + if (proto->destroy_cgroup) + proto->destroy_cgroup(cgrp, ss); + mutex_unlock(&cgroup_proto_list_lock); +} + +void register_sock_cgroup(struct proto *prot) +{ + if (!prot->proto_cgroup) + return; + + mutex_lock(&cgroup_proto_list_lock); + list_add(&prot->cgroup_node, &cgroup_proto_list); + mutex_unlock(&cgroup_proto_list_lock); +} + +void unregister_sock_cgroup(struct proto *prot) +{ + if (!prot->proto_cgroup) + return; + + mutex_lock(&cgroup_proto_list_lock); + list_del(&prot->cgroup_node); + mutex_unlock(&cgroup_proto_list_lock); +} + static int register_kmem_files(struct cgroup *cont, struct cgroup_subsys *ss) { int ret = 0; diff --git a/net/core/sock.c b/net/core/sock.c index 5a6a906..5a56a55 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -139,43 +139,6 @@ static DEFINE_RWLOCK(proto_list_lock); static LIST_HEAD(proto_list); -#ifdef CONFIG_CGROUP_MEM_RES_CTLR_KMEM -int mem_cgroup_sockets_init(struct cgroup *cgrp, struct cgroup_subsys *ss) -{ - struct proto *proto; - int ret = 0; - - read_lock(&proto_list_lock); - list_for_each_entry(proto, &proto_list, node) { - if (proto->init_cgroup) { - ret = proto->init_cgroup(cgrp, ss); - if (ret) - goto out; - } - } - - read_unlock(&proto_list_lock); - return ret; -out: - list_for_each_entry_continue_reverse(proto, &proto_list, node) - if (proto->destroy_cgroup) - proto->destroy_cgroup(cgrp, ss); - read_unlock(&proto_list_lock); - return ret; -} - -void mem_cgroup_sockets_destroy(struct cgroup *cgrp, struct cgroup_subsys *ss) -{ - struct proto *proto; - - read_lock(&proto_list_lock); - list_for_each_entry_reverse(proto, &proto_list, node) - if (proto->destroy_cgroup) - proto->destroy_cgroup(cgrp, ss); - read_unlock(&proto_list_lock); -} -#endif - /* * Each address family might have different locking rules, so we have * one slock key per address family: @@ -2483,6 +2446,9 @@ int proto_register(struct proto *prot, int alloc_slab) list_add(&prot->node, &proto_list); assign_proto_idx(prot); write_unlock(&proto_list_lock); + + register_sock_cgroup(prot); + return 0; out_free_timewait_sock_slab_name: @@ -2510,6 +2476,8 @@ void proto_unregister(struct proto *prot) list_del(&prot->node); write_unlock(&proto_list_lock); + unregister_sock_cgroup(prot); + if (prot->slab != NULL) { kmem_cache_destroy(prot->slab); prot->slab = NULL;