ckrm E17 memory controller
[linux-2.6.git] / include / linux / ckrm_mem_inline.h
1 /* include/linux/ckrm_mem_inline.h : memory control for CKRM
2  *
3  * Copyright (C) Jiantao Kong, IBM Corp. 2003
4  *           (C) Shailabh Nagar, IBM Corp. 2003
5  *           (C) Chandra Seetharaman, IBM Corp. 2004
6  *
7  *
8  * Memory control functions of the CKRM kernel API
9  *
10  * Latest version, more details at http://ckrm.sf.net
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  */
18
19 #ifndef _LINUX_CKRM_MEM_INLINE_H_
20 #define _LINUX_CKRM_MEM_INLINE_H_
21
22 #include <linux/rmap.h>
23 #include <linux/mmzone.h>
24 #include <linux/ckrm_mem.h>
25
26
27 #ifdef CONFIG_CKRM_RES_MEM
28
29 #define ckrm_shrink_list_empty() list_empty(&ckrm_shrink_list)
30
31 static inline struct ckrm_mem_res *
32 ckrm_get_mem_class(struct task_struct *tsk)
33 {
34         return ckrm_get_res_class(tsk->taskclass, mem_rcbs.resid,
35                 struct ckrm_mem_res);
36 }
37
38 static inline void
39 ckrm_set_shrink(struct ckrm_zone *cz)
40 {
41         set_bit(CLS_SHRINK_BIT, &cz->shrink_flag);
42 }
43
44 static inline int
45 ckrm_test_set_shrink(struct ckrm_zone *cz)
46 {
47         return test_and_set_bit(CLS_SHRINK_BIT, &cz->shrink_flag);
48 }
49
50 static inline void 
51 ckrm_clear_shrink(struct ckrm_zone *cz)
52 {
53         clear_bit(CLS_SHRINK_BIT, &cz->shrink_flag);
54 }
55
56 static inline void
57 set_page_ckrmzone( struct page *page, struct ckrm_zone *cz)
58 {
59         page->ckrm_zone = cz;
60 }
61
62 static inline struct ckrm_zone *
63 page_ckrmzone(struct page *page)
64 {
65         return page->ckrm_zone;
66 }
67
68 /*
69  * Currently, a shared page that is shared by multiple classes is charged
70  * to a class with max available guarantee. Simply replace this function
71  * for other policies.
72  */
73 static inline int
74 ckrm_mem_share_compare(struct ckrm_mem_res *a, struct ckrm_mem_res *b)
75 {
76         if (a == NULL)
77                 return -(b != NULL);
78         if (b == NULL)
79                 return 1;
80         if (a->pg_guar == b->pg_guar)
81                 return 0;
82         if (a->pg_guar == CKRM_SHARE_DONTCARE)
83                 return 1;
84         if (b->pg_guar == CKRM_SHARE_DONTCARE)
85                 return -1;
86         return (a->pg_unused - b->pg_unused);
87 }
88
89 static inline void
90 incr_use_count(struct ckrm_mem_res *cls, int borrow)
91 {
92         extern int ckrm_mem_shrink_at;
93         struct ckrm_mem_res *parcls = ckrm_get_res_class(cls->parent,
94                                 mem_rcbs.resid, struct ckrm_mem_res);
95
96         if (!cls)
97                 return;
98
99         atomic_inc(&cls->pg_total);
100         if (borrow)
101                 cls->pg_lent++;
102
103         parcls = ckrm_get_res_class(cls->parent,
104                                 mem_rcbs.resid, struct ckrm_mem_res);
105         if (parcls && ((cls->pg_guar == CKRM_SHARE_DONTCARE) ||
106                         (atomic_read(&cls->pg_total) > cls->pg_unused))) {
107                 incr_use_count(parcls, 1);
108                 cls->pg_borrowed++;
109         } else
110                 atomic_inc(&ckrm_mem_real_count);
111
112         if ((cls->pg_limit != CKRM_SHARE_DONTCARE) &&
113                         (atomic_read(&cls->pg_total) >=
114                         ((ckrm_mem_shrink_at * cls->pg_limit) / 100)) &&
115                         ((cls->flags & CLS_AT_LIMIT) != CLS_AT_LIMIT)) {
116                 ckrm_shrink_atlimit(cls);
117         }
118         return;
119 }
120
121 static inline void
122 decr_use_count(struct ckrm_mem_res *cls, int borrowed)
123 {
124         if (!cls)
125                 return;
126         atomic_dec(&cls->pg_total);
127         if (borrowed)
128                 cls->pg_lent--;
129         if (cls->pg_borrowed > 0) {
130                 struct ckrm_mem_res *parcls = ckrm_get_res_class(cls->parent,
131                                 mem_rcbs.resid, struct ckrm_mem_res);
132                 if (parcls) {
133                         decr_use_count(parcls, 1);
134                         cls->pg_borrowed--;
135                         return;
136                 }
137         }
138         atomic_dec(&ckrm_mem_real_count);
139 }
140
141 static inline void
142 ckrm_set_page_class(struct page *page, struct ckrm_mem_res *cls)
143 {
144         struct ckrm_zone *new_czone, *old_czone;
145
146         if (!cls) {
147                 if (!ckrm_mem_root_class) {
148                         set_page_ckrmzone(page, NULL);
149                         return;
150                 }
151                 cls = ckrm_mem_root_class;
152         }
153         new_czone = &cls->ckrm_zone[page_zonenum(page)];
154         old_czone = page_ckrmzone(page);
155         
156         if (old_czone)
157                 kref_put(&old_czone->memcls->nr_users, memclass_release);
158
159         set_page_ckrmzone(page, new_czone);
160         kref_get(&cls->nr_users);
161         incr_use_count(cls, 0);
162         SetPageCkrmAccount(page);
163 }
164
165 static inline void
166 ckrm_change_page_class(struct page *page, struct ckrm_mem_res *newcls)
167 {
168         struct ckrm_zone *old_czone = page_ckrmzone(page), *new_czone;
169         struct ckrm_mem_res *oldcls;
170
171         if  (!newcls) {
172                 if (!ckrm_mem_root_class)
173                         return;
174                 newcls = ckrm_mem_root_class;
175         }
176
177         oldcls = old_czone->memcls;
178         if (oldcls == newcls)
179                 return;
180
181         if (oldcls) {
182                 kref_put(&oldcls->nr_users, memclass_release);
183                 decr_use_count(oldcls, 0);
184         }
185
186         new_czone = &newcls->ckrm_zone[page_zonenum(page)];
187         set_page_ckrmzone(page, new_czone);
188         kref_get(&newcls->nr_users);
189         incr_use_count(newcls, 0);
190
191         list_del(&page->lru);
192         if (PageActive(page)) {
193                 old_czone->nr_active--;
194                 new_czone->nr_active++;
195                 list_add(&page->lru, &new_czone->active_list);
196         } else {
197                 old_czone->nr_inactive--;
198                 new_czone->nr_inactive++;
199                 list_add(&page->lru, &new_czone->inactive_list);
200         }
201 }
202
203 static inline void
204 ckrm_clear_page_class(struct page *page)
205 {
206         struct ckrm_zone *czone = page_ckrmzone(page);
207         if (czone != NULL) {
208                 if (PageCkrmAccount(page)) {
209                         decr_use_count(czone->memcls, 0);
210                         ClearPageCkrmAccount(page);
211                 }
212                 kref_put(&czone->memcls->nr_users, memclass_release);
213                 set_page_ckrmzone(page, NULL);
214         }
215 }
216
217 static inline void
218 ckrm_mem_inc_active(struct page *page)
219 {
220         struct ckrm_mem_res *cls = ckrm_get_mem_class(current)
221                                                 ?: ckrm_mem_root_class;
222         struct ckrm_zone *czone;
223
224         if (cls == NULL)
225                 return;
226
227         ckrm_set_page_class(page, cls);
228         czone = page_ckrmzone(page);
229         czone->nr_active++;
230         list_add(&page->lru, &czone->active_list);
231 }
232
233 static inline void
234 ckrm_mem_dec_active(struct page *page)
235 {
236         struct ckrm_zone *czone = page_ckrmzone(page);
237         if (czone == NULL)
238                 return;
239
240         list_del(&page->lru);
241         czone->nr_active--;
242         ckrm_clear_page_class(page);
243 }
244
245
246 static inline void
247 ckrm_mem_inc_inactive(struct page *page)
248 {
249         struct ckrm_mem_res *cls = ckrm_get_mem_class(current)
250                                                 ?: ckrm_mem_root_class;
251         struct ckrm_zone *czone;
252
253         if (cls == NULL)
254                 return;
255
256         ckrm_set_page_class(page, cls);
257         czone = page_ckrmzone(page);
258         czone->nr_inactive++;
259         list_add(&page->lru, &czone->inactive_list);
260 }
261
262 static inline void
263 ckrm_mem_dec_inactive(struct page *page)
264 {
265         struct ckrm_zone *czone = page_ckrmzone(page);
266         if (czone == NULL)
267                 return;
268
269         czone->nr_inactive--;
270         list_del(&page->lru);
271         ckrm_clear_page_class(page);
272 }
273
274 static inline void
275 ckrm_zone_add_active(struct ckrm_zone *czone, int cnt)
276 {
277         czone->nr_active += cnt;
278 }
279
280 static inline void
281 ckrm_zone_add_inactive(struct ckrm_zone *czone, int cnt)
282 {
283         czone->nr_inactive += cnt;
284 }
285
286 static inline void
287 ckrm_zone_sub_active(struct ckrm_zone *czone, int cnt)
288 {
289         czone->nr_active -= cnt;
290 }
291
292 static inline void
293 ckrm_zone_sub_inactive(struct ckrm_zone *czone, int cnt)
294 {
295         czone->nr_inactive -= cnt;
296 }
297
298 static inline int
299 ckrm_class_limit_ok(struct ckrm_mem_res *cls)
300 {
301         int ret;
302
303         if ((mem_rcbs.resid == -1) || !cls) {
304                 return 1;
305         }
306         if (cls->pg_limit == CKRM_SHARE_DONTCARE) {
307                 struct ckrm_mem_res *parcls = ckrm_get_res_class(cls->parent,
308                                         mem_rcbs.resid, struct ckrm_mem_res);
309                 ret = (parcls ? ckrm_class_limit_ok(parcls) : 0);
310         } else
311                 ret = (atomic_read(&cls->pg_total) <= cls->pg_limit);
312
313         /* If we are failing, just nudge the back end */
314         if (ret == 0)
315                 ckrm_shrink_atlimit(cls);
316
317         return ret;
318 }
319
320 static inline void
321 ckrm_page_init(struct page *page)
322 {
323         page->flags &= ~(1 << PG_ckrm_account);
324         set_page_ckrmzone(page, NULL);
325 }
326
327
328 /* task/mm initializations/cleanup */
329
330 static inline void
331 ckrm_task_mm_init(struct task_struct *tsk)
332 {
333         INIT_LIST_HEAD(&tsk->mm_peers);
334 }
335
336 static inline void
337 ckrm_task_mm_set(struct mm_struct * mm, struct task_struct *task)
338 {
339         spin_lock(&mm->peertask_lock);
340         if (!list_empty(&task->mm_peers)) {
341                 printk(KERN_ERR "MEM_RC: Task list NOT empty!! emptying...\n");
342                 list_del_init(&task->mm_peers);
343         }
344         list_add_tail(&task->mm_peers, &mm->tasklist);
345         spin_unlock(&mm->peertask_lock);
346         if (mm->memclass != ckrm_get_mem_class(task))
347                 ckrm_mem_migrate_mm(mm, NULL);
348         return;
349 }
350
351 static inline void
352 ckrm_task_mm_change(struct task_struct *tsk,
353                 struct mm_struct *oldmm, struct mm_struct *newmm)
354 {
355         if (oldmm) {
356                 spin_lock(&oldmm->peertask_lock);
357                 list_del(&tsk->mm_peers);
358                 ckrm_mem_migrate_mm(oldmm, NULL);
359                 spin_unlock(&oldmm->peertask_lock);
360         }
361         spin_lock(&newmm->peertask_lock);
362         list_add_tail(&tsk->mm_peers, &newmm->tasklist);
363         ckrm_mem_migrate_mm(newmm, NULL);
364         spin_unlock(&newmm->peertask_lock);
365 }
366
367 static inline void
368 ckrm_task_mm_clear(struct task_struct *tsk, struct mm_struct *mm)
369 {
370         spin_lock(&mm->peertask_lock);
371         list_del_init(&tsk->mm_peers);
372         ckrm_mem_migrate_mm(mm, NULL);
373         spin_unlock(&mm->peertask_lock);
374 }
375
376 static inline void
377 ckrm_mm_init(struct mm_struct *mm)
378 {
379         INIT_LIST_HEAD(&mm->tasklist);
380         mm->peertask_lock = SPIN_LOCK_UNLOCKED;
381 }
382
383 static inline void
384 ckrm_mm_setclass(struct mm_struct *mm, struct ckrm_mem_res *cls)
385 {
386         mm->memclass = cls;
387         kref_get(&cls->nr_users);
388 }
389
390 static inline void
391 ckrm_mm_clearclass(struct mm_struct *mm)
392 {
393         if (mm->memclass) {
394                 kref_put(&mm->memclass->nr_users, memclass_release);
395                 mm->memclass = NULL;
396         }
397 }
398
399 static inline void ckrm_init_lists(struct zone *zone)                   {}
400
401 static inline void ckrm_add_tail_inactive(struct page *page)
402 {
403          struct ckrm_zone *ckrm_zone = page_ckrmzone(page);
404          list_add_tail(&page->lru, &ckrm_zone->inactive_list);
405 }
406
407 #else
408
409 #define ckrm_shrink_list_empty()                (1)
410
411 static inline void *
412 ckrm_get_memclass(struct task_struct *tsk)
413 {
414         return NULL;
415 }
416
417 static inline void ckrm_clear_page_class(struct page *p)                {}
418
419 static inline void ckrm_mem_inc_active(struct page *p)                  {}
420 static inline void ckrm_mem_dec_active(struct page *p)                  {}
421 static inline void ckrm_mem_inc_inactive(struct page *p)                {}
422 static inline void ckrm_mem_dec_inactive(struct page *p)                {}
423
424 #define ckrm_zone_add_active(a, b)      do {} while (0)
425 #define ckrm_zone_add_inactive(a, b)    do {} while (0)
426 #define ckrm_zone_sub_active(a, b)      do {} while (0)
427 #define ckrm_zone_sub_inactive(a, b)    do {} while (0)
428
429 #define ckrm_class_limit_ok(a)                                          (1)
430
431 static inline void ckrm_page_init(struct page *p)                       {}
432 static inline void ckrm_task_mm_init(struct task_struct *tsk)           {}
433 static inline void ckrm_task_mm_set(struct mm_struct * mm,
434                                         struct task_struct *task)       {}
435 static inline void ckrm_task_mm_change(struct task_struct *tsk,
436                 struct mm_struct *oldmm, struct mm_struct *newmm)       {}
437 static inline void ckrm_task_mm_clear(struct task_struct *tsk,
438                                                 struct mm_struct *mm)   {}
439
440 static inline void ckrm_mm_init(struct mm_struct *mm)                   {}
441
442 /* using #define instead of static inline as the prototype requires   *
443  * data structures that is available only with the controller enabled */
444 #define ckrm_mm_setclass(a, b)                                  do {} while(0)
445
446 static inline void ckrm_mm_clearclass(struct mm_struct *mm)             {}
447
448 static inline void ckrm_init_lists(struct zone *zone)
449 {
450         INIT_LIST_HEAD(&zone->active_list);
451         INIT_LIST_HEAD(&zone->inactive_list);
452 }
453
454 static inline void ckrm_add_tail_inactive(struct page *page)
455 {
456          struct zone *zone = page_zone(page);
457          list_add_tail(&page->lru, &zone->inactive_list);
458 }
459 #endif 
460 #endif /* _LINUX_CKRM_MEM_INLINE_H_ */