Blame view

kernel/res_counter.c 4.4 KB
e552b6617   Pavel Emelianov   Memory controller...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * resource cgroups
   *
   * Copyright 2007 OpenVZ SWsoft Inc
   *
   * Author: Pavel Emelianov <xemul@openvz.org>
   *
   */
  
  #include <linux/types.h>
  #include <linux/parser.h>
  #include <linux/fs.h>
  #include <linux/res_counter.h>
  #include <linux/uaccess.h>
856c13aa1   Paul Menage   cgroup files: con...
15
  #include <linux/mm.h>
e552b6617   Pavel Emelianov   Memory controller...
16

28dbc4b6a   Balbir Singh   memcg: memory cgr...
17
  void res_counter_init(struct res_counter *counter, struct res_counter *parent)
e552b6617   Pavel Emelianov   Memory controller...
18
19
  {
  	spin_lock_init(&counter->lock);
6de5a8bfc   Sha Zhengju   memcg: rename RES...
20
21
  	counter->limit = RES_COUNTER_MAX;
  	counter->soft_limit = RES_COUNTER_MAX;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
22
  	counter->parent = parent;
e552b6617   Pavel Emelianov   Memory controller...
23
  }
539a13b47   David Rientjes   res_counter: remo...
24
25
26
27
28
29
30
31
32
33
34
35
  static u64 res_counter_uncharge_locked(struct res_counter *counter,
  				       unsigned long val)
  {
  	if (WARN_ON(counter->usage < val))
  		val = counter->usage;
  
  	counter->usage -= val;
  	return counter->usage;
  }
  
  static int res_counter_charge_locked(struct res_counter *counter,
  				     unsigned long val, bool force)
e552b6617   Pavel Emelianov   Memory controller...
36
  {
4d8438f04   Frederic Weisbecker   res_counter: Merg...
37
  	int ret = 0;
e552b6617   Pavel Emelianov   Memory controller...
38
39
  	if (counter->usage + val > counter->limit) {
  		counter->failcnt++;
4d8438f04   Frederic Weisbecker   res_counter: Merg...
40
41
42
  		ret = -ENOMEM;
  		if (!force)
  			return ret;
e552b6617   Pavel Emelianov   Memory controller...
43
44
45
  	}
  
  	counter->usage += val;
0d4dde1ac   Frederic Weisbecker   res_counter: Acco...
46
  	if (counter->usage > counter->max_usage)
c84872e16   Pavel Emelyanov   memcgroup: add th...
47
  		counter->max_usage = counter->usage;
4d8438f04   Frederic Weisbecker   res_counter: Merg...
48
  	return ret;
e552b6617   Pavel Emelianov   Memory controller...
49
  }
4d8438f04   Frederic Weisbecker   res_counter: Merg...
50
51
  static int __res_counter_charge(struct res_counter *counter, unsigned long val,
  				struct res_counter **limit_fail_at, bool force)
e552b6617   Pavel Emelianov   Memory controller...
52
  {
4d8438f04   Frederic Weisbecker   res_counter: Merg...
53
  	int ret, r;
e552b6617   Pavel Emelianov   Memory controller...
54
  	unsigned long flags;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
55
  	struct res_counter *c, *u;
e552b6617   Pavel Emelianov   Memory controller...
56

4d8438f04   Frederic Weisbecker   res_counter: Merg...
57
  	r = ret = 0;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
58
59
60
61
  	*limit_fail_at = NULL;
  	local_irq_save(flags);
  	for (c = counter; c != NULL; c = c->parent) {
  		spin_lock(&c->lock);
4d8438f04   Frederic Weisbecker   res_counter: Merg...
62
  		r = res_counter_charge_locked(c, val, force);
28dbc4b6a   Balbir Singh   memcg: memory cgr...
63
  		spin_unlock(&c->lock);
4d8438f04   Frederic Weisbecker   res_counter: Merg...
64
65
  		if (r < 0 && !ret) {
  			ret = r;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
66
  			*limit_fail_at = c;
4d8438f04   Frederic Weisbecker   res_counter: Merg...
67
68
  			if (!force)
  				break;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
69
70
  		}
  	}
4d8438f04   Frederic Weisbecker   res_counter: Merg...
71
72
73
74
75
76
77
  
  	if (ret < 0 && !force) {
  		for (u = counter; u != c; u = u->parent) {
  			spin_lock(&u->lock);
  			res_counter_uncharge_locked(u, val);
  			spin_unlock(&u->lock);
  		}
28dbc4b6a   Balbir Singh   memcg: memory cgr...
78
  	}
28dbc4b6a   Balbir Singh   memcg: memory cgr...
79
  	local_irq_restore(flags);
4d8438f04   Frederic Weisbecker   res_counter: Merg...
80

e552b6617   Pavel Emelianov   Memory controller...
81
82
  	return ret;
  }
4d8438f04   Frederic Weisbecker   res_counter: Merg...
83
84
85
86
87
  int res_counter_charge(struct res_counter *counter, unsigned long val,
  			struct res_counter **limit_fail_at)
  {
  	return __res_counter_charge(counter, val, limit_fail_at, false);
  }
0e90b31f4   Glauber Costa   net: introduce re...
88
89
90
  int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
  			      struct res_counter **limit_fail_at)
  {
4d8438f04   Frederic Weisbecker   res_counter: Merg...
91
  	return __res_counter_charge(counter, val, limit_fail_at, true);
0e90b31f4   Glauber Costa   net: introduce re...
92
  }
4d8438f04   Frederic Weisbecker   res_counter: Merg...
93

50bdd430c   Glauber Costa   res_counter: retu...
94
95
96
  u64 res_counter_uncharge_until(struct res_counter *counter,
  			       struct res_counter *top,
  			       unsigned long val)
e552b6617   Pavel Emelianov   Memory controller...
97
98
  {
  	unsigned long flags;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
99
  	struct res_counter *c;
50bdd430c   Glauber Costa   res_counter: retu...
100
  	u64 ret = 0;
e552b6617   Pavel Emelianov   Memory controller...
101

28dbc4b6a   Balbir Singh   memcg: memory cgr...
102
  	local_irq_save(flags);
2bb2ba9d5   Frederic Weisbecker   rescounters: add ...
103
  	for (c = counter; c != top; c = c->parent) {
50bdd430c   Glauber Costa   res_counter: retu...
104
  		u64 r;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
105
  		spin_lock(&c->lock);
50bdd430c   Glauber Costa   res_counter: retu...
106
107
108
  		r = res_counter_uncharge_locked(c, val);
  		if (c == counter)
  			ret = r;
28dbc4b6a   Balbir Singh   memcg: memory cgr...
109
110
111
  		spin_unlock(&c->lock);
  	}
  	local_irq_restore(flags);
50bdd430c   Glauber Costa   res_counter: retu...
112
  	return ret;
e552b6617   Pavel Emelianov   Memory controller...
113
  }
50bdd430c   Glauber Costa   res_counter: retu...
114
  u64 res_counter_uncharge(struct res_counter *counter, unsigned long val)
2bb2ba9d5   Frederic Weisbecker   rescounters: add ...
115
  {
50bdd430c   Glauber Costa   res_counter: retu...
116
  	return res_counter_uncharge_until(counter, NULL, val);
2bb2ba9d5   Frederic Weisbecker   rescounters: add ...
117
  }
e552b6617   Pavel Emelianov   Memory controller...
118

0eea10301   Balbir Singh   Memory controller...
119
120
  static inline unsigned long long *
  res_counter_member(struct res_counter *counter, int member)
e552b6617   Pavel Emelianov   Memory controller...
121
122
123
124
  {
  	switch (member) {
  	case RES_USAGE:
  		return &counter->usage;
c84872e16   Pavel Emelyanov   memcgroup: add th...
125
126
  	case RES_MAX_USAGE:
  		return &counter->max_usage;
e552b6617   Pavel Emelianov   Memory controller...
127
128
129
130
  	case RES_LIMIT:
  		return &counter->limit;
  	case RES_FAILCNT:
  		return &counter->failcnt;
296c81d89   Balbir Singh   memory controller...
131
132
  	case RES_SOFT_LIMIT:
  		return &counter->soft_limit;
e552b6617   Pavel Emelianov   Memory controller...
133
134
135
136
137
138
139
  	};
  
  	BUG();
  	return NULL;
  }
  
  ssize_t res_counter_read(struct res_counter *counter, int member,
0eea10301   Balbir Singh   Memory controller...
140
141
  		const char __user *userbuf, size_t nbytes, loff_t *pos,
  		int (*read_strategy)(unsigned long long val, char *st_buf))
e552b6617   Pavel Emelianov   Memory controller...
142
  {
0eea10301   Balbir Singh   Memory controller...
143
  	unsigned long long *val;
e552b6617   Pavel Emelianov   Memory controller...
144
145
146
147
  	char buf[64], *s;
  
  	s = buf;
  	val = res_counter_member(counter, member);
0eea10301   Balbir Singh   Memory controller...
148
149
150
151
152
  	if (read_strategy)
  		s += read_strategy(*val, s);
  	else
  		s += sprintf(s, "%llu
  ", *val);
e552b6617   Pavel Emelianov   Memory controller...
153
154
155
  	return simple_read_from_buffer((void __user *)userbuf, nbytes,
  			pos, buf, s - buf);
  }
6c191cd01   KAMEZAWA Hiroyuki   memcg: res_counte...
156
157
158
159
160
161
162
163
164
165
166
167
168
  #if BITS_PER_LONG == 32
  u64 res_counter_read_u64(struct res_counter *counter, int member)
  {
  	unsigned long flags;
  	u64 ret;
  
  	spin_lock_irqsave(&counter->lock, flags);
  	ret = *res_counter_member(counter, member);
  	spin_unlock_irqrestore(&counter->lock, flags);
  
  	return ret;
  }
  #else
2c7eabf37   Paul Menage   CGroup API files:...
169
170
171
172
  u64 res_counter_read_u64(struct res_counter *counter, int member)
  {
  	return *res_counter_member(counter, member);
  }
6c191cd01   KAMEZAWA Hiroyuki   memcg: res_counte...
173
  #endif
2c7eabf37   Paul Menage   CGroup API files:...
174

856c13aa1   Paul Menage   cgroup files: con...
175
  int res_counter_memparse_write_strategy(const char *buf,
1a36e59d4   Sha Zhengju   memcg: reduce fun...
176
  					unsigned long long *resp)
e552b6617   Pavel Emelianov   Memory controller...
177
  {
856c13aa1   Paul Menage   cgroup files: con...
178
  	char *end;
1a36e59d4   Sha Zhengju   memcg: reduce fun...
179
  	unsigned long long res;
c5b947b28   Daisuke Nishimura   memcg: add interf...
180

6de5a8bfc   Sha Zhengju   memcg: rename RES...
181
  	/* return RES_COUNTER_MAX(unlimited) if "-1" is specified */
c5b947b28   Daisuke Nishimura   memcg: add interf...
182
  	if (*buf == '-') {
1a36e59d4   Sha Zhengju   memcg: reduce fun...
183
184
  		res = simple_strtoull(buf + 1, &end, 10);
  		if (res != 1 || *end != '\0')
c5b947b28   Daisuke Nishimura   memcg: add interf...
185
  			return -EINVAL;
1a36e59d4   Sha Zhengju   memcg: reduce fun...
186
  		*resp = RES_COUNTER_MAX;
c5b947b28   Daisuke Nishimura   memcg: add interf...
187
188
  		return 0;
  	}
1a36e59d4   Sha Zhengju   memcg: reduce fun...
189
  	res = memparse(buf, &end);
856c13aa1   Paul Menage   cgroup files: con...
190
191
  	if (*end != '\0')
  		return -EINVAL;
e552b6617   Pavel Emelianov   Memory controller...
192

1a36e59d4   Sha Zhengju   memcg: reduce fun...
193
194
  	if (PAGE_ALIGN(res) >= res)
  		res = PAGE_ALIGN(res);
3af335167   Sha Zhengju   memcg: avoid over...
195
  	else
1a36e59d4   Sha Zhengju   memcg: reduce fun...
196
197
198
  		res = RES_COUNTER_MAX;
  
  	*resp = res;
3af335167   Sha Zhengju   memcg: avoid over...
199

856c13aa1   Paul Menage   cgroup files: con...
200
201
  	return 0;
  }