This source file includes following definitions.
- propagate_protected_usage
- page_counter_cancel
- page_counter_charge
- page_counter_try_charge
- page_counter_uncharge
- page_counter_set_max
- page_counter_set_min
- page_counter_set_low
- page_counter_memparse
1
2
3
4
5
6
7
8 #include <linux/page_counter.h>
9 #include <linux/atomic.h>
10 #include <linux/kernel.h>
11 #include <linux/string.h>
12 #include <linux/sched.h>
13 #include <linux/bug.h>
14 #include <asm/page.h>
15
16 static void propagate_protected_usage(struct page_counter *c,
17 unsigned long usage)
18 {
19 unsigned long protected, old_protected;
20 long delta;
21
22 if (!c->parent)
23 return;
24
25 if (c->min || atomic_long_read(&c->min_usage)) {
26 if (usage <= c->min)
27 protected = usage;
28 else
29 protected = 0;
30
31 old_protected = atomic_long_xchg(&c->min_usage, protected);
32 delta = protected - old_protected;
33 if (delta)
34 atomic_long_add(delta, &c->parent->children_min_usage);
35 }
36
37 if (c->low || atomic_long_read(&c->low_usage)) {
38 if (usage <= c->low)
39 protected = usage;
40 else
41 protected = 0;
42
43 old_protected = atomic_long_xchg(&c->low_usage, protected);
44 delta = protected - old_protected;
45 if (delta)
46 atomic_long_add(delta, &c->parent->children_low_usage);
47 }
48 }
49
50
51
52
53
54
55 void page_counter_cancel(struct page_counter *counter, unsigned long nr_pages)
56 {
57 long new;
58
59 new = atomic_long_sub_return(nr_pages, &counter->usage);
60 propagate_protected_usage(counter, new);
61
62 WARN_ON_ONCE(new < 0);
63 }
64
65
66
67
68
69
70
71
72 void page_counter_charge(struct page_counter *counter, unsigned long nr_pages)
73 {
74 struct page_counter *c;
75
76 for (c = counter; c; c = c->parent) {
77 long new;
78
79 new = atomic_long_add_return(nr_pages, &c->usage);
80 propagate_protected_usage(counter, new);
81
82
83
84
85 if (new > c->watermark)
86 c->watermark = new;
87 }
88 }
89
90
91
92
93
94
95
96
97
98
99 bool page_counter_try_charge(struct page_counter *counter,
100 unsigned long nr_pages,
101 struct page_counter **fail)
102 {
103 struct page_counter *c;
104
105 for (c = counter; c; c = c->parent) {
106 long new;
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 new = atomic_long_add_return(nr_pages, &c->usage);
122 if (new > c->max) {
123 atomic_long_sub(nr_pages, &c->usage);
124 propagate_protected_usage(counter, new);
125
126
127
128
129 c->failcnt++;
130 *fail = c;
131 goto failed;
132 }
133 propagate_protected_usage(counter, new);
134
135
136
137
138 if (new > c->watermark)
139 c->watermark = new;
140 }
141 return true;
142
143 failed:
144 for (c = counter; c != *fail; c = c->parent)
145 page_counter_cancel(c, nr_pages);
146
147 return false;
148 }
149
150
151
152
153
154
155 void page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages)
156 {
157 struct page_counter *c;
158
159 for (c = counter; c; c = c->parent)
160 page_counter_cancel(c, nr_pages);
161 }
162
163
164
165
166
167
168
169
170
171
172
173 int page_counter_set_max(struct page_counter *counter, unsigned long nr_pages)
174 {
175 for (;;) {
176 unsigned long old;
177 long usage;
178
179
180
181
182
183
184
185
186
187
188
189
190 usage = atomic_long_read(&counter->usage);
191
192 if (usage > nr_pages)
193 return -EBUSY;
194
195 old = xchg(&counter->max, nr_pages);
196
197 if (atomic_long_read(&counter->usage) <= usage)
198 return 0;
199
200 counter->max = old;
201 cond_resched();
202 }
203 }
204
205
206
207
208
209
210
211
212 void page_counter_set_min(struct page_counter *counter, unsigned long nr_pages)
213 {
214 struct page_counter *c;
215
216 counter->min = nr_pages;
217
218 for (c = counter; c; c = c->parent)
219 propagate_protected_usage(c, atomic_long_read(&c->usage));
220 }
221
222
223
224
225
226
227
228
229 void page_counter_set_low(struct page_counter *counter, unsigned long nr_pages)
230 {
231 struct page_counter *c;
232
233 counter->low = nr_pages;
234
235 for (c = counter; c; c = c->parent)
236 propagate_protected_usage(c, atomic_long_read(&c->usage));
237 }
238
239
240
241
242
243
244
245
246
247
248 int page_counter_memparse(const char *buf, const char *max,
249 unsigned long *nr_pages)
250 {
251 char *end;
252 u64 bytes;
253
254 if (!strcmp(buf, max)) {
255 *nr_pages = PAGE_COUNTER_MAX;
256 return 0;
257 }
258
259 bytes = memparse(buf, &end);
260 if (*end != '\0')
261 return -EINVAL;
262
263 *nr_pages = min(bytes / PAGE_SIZE, (u64)PAGE_COUNTER_MAX);
264
265 return 0;
266 }