aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/res_counter.h6
-rw-r--r--include/net/sock.h10
-rw-r--r--kernel/res_counter.c25
-rw-r--r--net/core/sock.c4
4 files changed, 37 insertions, 8 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);
diff --git a/kernel/res_counter.c b/kernel/res_counter.c
index 6d269cce7aa1..d508363858b3 100644
--- a/kernel/res_counter.c
+++ b/kernel/res_counter.c
@@ -66,6 +66,31 @@ done:
66 return ret; 66 return ret;
67} 67}
68 68
69int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
70 struct res_counter **limit_fail_at)
71{
72 int ret, r;
73 unsigned long flags;
74 struct res_counter *c;
75
76 r = ret = 0;
77 *limit_fail_at = NULL;
78 local_irq_save(flags);
79 for (c = counter; c != NULL; c = c->parent) {
80 spin_lock(&c->lock);
81 r = res_counter_charge_locked(c, val);
82 if (r)
83 c->usage += val;
84 spin_unlock(&c->lock);
85 if (r < 0 && ret == 0) {
86 *limit_fail_at = c;
87 ret = r;
88 }
89 }
90 local_irq_restore(flags);
91
92 return ret;
93}
69void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val) 94void res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
70{ 95{
71 if (WARN_ON(counter->usage < val)) 96 if (WARN_ON(counter->usage < val))
diff --git a/net/core/sock.c b/net/core/sock.c
index 5c5af9988f94..3e81fd2e3c75 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1827,7 +1827,7 @@ suppress_allocation:
1827 /* Alas. Undo changes. */ 1827 /* Alas. Undo changes. */
1828 sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; 1828 sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM;
1829 1829
1830 sk_memory_allocated_sub(sk, amt, parent_status); 1830 sk_memory_allocated_sub(sk, amt);
1831 1831
1832 return 0; 1832 return 0;
1833} 1833}
@@ -1840,7 +1840,7 @@ EXPORT_SYMBOL(__sk_mem_schedule);
1840void __sk_mem_reclaim(struct sock *sk) 1840void __sk_mem_reclaim(struct sock *sk)
1841{ 1841{
1842 sk_memory_allocated_sub(sk, 1842 sk_memory_allocated_sub(sk,
1843 sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT, 0); 1843 sk->sk_forward_alloc >> SK_MEM_QUANTUM_SHIFT);
1844 sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1; 1844 sk->sk_forward_alloc &= SK_MEM_QUANTUM - 1;
1845 1845
1846 if (sk_under_memory_pressure(sk) && 1846 if (sk_under_memory_pressure(sk) &&