aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorGlauber Costa <glommer@parallels.com>2012-01-19 23:57:16 -0500
committerDavid S. Miller <davem@davemloft.net>2012-01-22 15:08:46 -0500
commit0e90b31f4ba77027a7c21cbfc66404df0851ca21 (patch)
tree10dc6c443e2f058869d3953a90e6d48fb53f83ae /include
parent8cfd14ad1eb52e44cb1fe7b47a68126e45e04026 (diff)
net: introduce res_counter_charge_nofail() for socket allocations
There is a case in __sk_mem_schedule(), where an allocation is beyond the maximum, but yet we are allowed to proceed. It happens under the following condition: sk->sk_wmem_queued + size >= sk->sk_sndbuf The network code won't revert the allocation in this case, meaning that at some point later it'll try to do it. Since this is never communicated to the underlying res_counter code, there is an inbalance in res_counter uncharge operation. I see two ways of fixing this: 1) storing the information about those allocations somewhere in memcg, and then deducting from that first, before we start draining the res_counter, 2) providing a slightly different allocation function for the res_counter, that matches the original behavior of the network code more closely. I decided to go for #2 here, believing it to be more elegant, since #1 would require us to do basically that, but in a more obscure way. Signed-off-by: Glauber Costa <glommer@parallels.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Michal Hocko <mhocko@suse.cz> CC: Tejun Heo <tj@kernel.org> CC: Li Zefan <lizf@cn.fujitsu.com> CC: Laurent Chavey <chavey@google.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r--include/linux/res_counter.h6
-rw-r--r--include/net/sock.h10
2 files changed, 10 insertions, 6 deletions
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
index d06d014afda6..da81af086eaf 100644
--- a/include/linux/res_counter.h
+++ b/include/linux/res_counter.h
@@ -109,12 +109,18 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent);
109 * 109 *
110 * returns 0 on success and <0 if the counter->usage will exceed the 110 * returns 0 on success and <0 if the counter->usage will exceed the
111 * counter->limit _locked call expects the counter->lock to be taken 111 * counter->limit _locked call expects the counter->lock to be taken
112 *
113 * charge_nofail works the same, except that it charges the resource
114 * counter unconditionally, and returns < 0 if the after the current
115 * charge we are over limit.
112 */ 116 */
113 117
114int __must_check res_counter_charge_locked(struct res_counter *counter, 118int __must_check res_counter_charge_locked(struct res_counter *counter,
115 unsigned long val); 119 unsigned long val);
116int __must_check res_counter_charge(struct res_counter *counter, 120int __must_check res_counter_charge(struct res_counter *counter,
117 unsigned long val, struct res_counter **limit_fail_at); 121 unsigned long val, struct res_counter **limit_fail_at);
122int __must_check res_counter_charge_nofail(struct res_counter *counter,
123 unsigned long val, struct res_counter **limit_fail_at);
118 124
119/* 125/*
120 * uncharge - tell that some portion of the resource is released 126 * uncharge - tell that some portion of the resource is released
diff --git a/include/net/sock.h b/include/net/sock.h
index 0e7a9b05f92b..4c69ac165e6b 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1008,9 +1008,8 @@ static inline void memcg_memory_allocated_add(struct cg_proto *prot,
1008 struct res_counter *fail; 1008 struct res_counter *fail;
1009 int ret; 1009 int ret;
1010 1010
1011 ret = res_counter_charge(prot->memory_allocated, 1011 ret = res_counter_charge_nofail(prot->memory_allocated,
1012 amt << PAGE_SHIFT, &fail); 1012 amt << PAGE_SHIFT, &fail);
1013
1014 if (ret < 0) 1013 if (ret < 0)
1015 *parent_status = OVER_LIMIT; 1014 *parent_status = OVER_LIMIT;
1016} 1015}
@@ -1054,12 +1053,11 @@ sk_memory_allocated_add(struct sock *sk, int amt, int *parent_status)
1054} 1053}
1055 1054
1056static inline void 1055static inline void
1057sk_memory_allocated_sub(struct sock *sk, int amt, int parent_status) 1056sk_memory_allocated_sub(struct sock *sk, int amt)
1058{ 1057{
1059 struct proto *prot = sk->sk_prot; 1058 struct proto *prot = sk->sk_prot;
1060 1059
1061 if (mem_cgroup_sockets_enabled && sk->sk_cgrp && 1060 if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
1062 parent_status != OVER_LIMIT) /* Otherwise was uncharged already */
1063 memcg_memory_allocated_sub(sk->sk_cgrp, amt); 1061 memcg_memory_allocated_sub(sk->sk_cgrp, amt);
1064 1062
1065 atomic_long_sub(amt, prot->memory_allocated); 1063 atomic_long_sub(amt, prot->memory_allocated);