7ea79d11c7620d71c0f1f92dbbf82babcd303f78
[linux-2.6.git] / kernel / ckrm / ckrm_null_class.c
1 /* kernel/ckrm/ckrm_null_class.c - NULL TaskClass controller for CKRM
2  *
3  * Copyright (C) Haoqiang Zheng,     IBM Corp. 2004
4  *           (C) Hubertus Franke,    IBM Corp. 2004
5  *
6  * Copyright (C) Marc E. Fiuczynski, Princeton University 2005
7  *               Adapted from ckrm_cpu_class.c.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  */
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/slab.h>
18 #include <asm/errno.h>
19 #include <linux/ckrm_events.h>
20 #include <linux/ckrm_rc.h>
21 #include <linux/ckrm_tc.h>
22 #include <linux/ckrm_classqueue.h>
23 #include <linux/seq_file.h>
24
25 #define CKRM_NULL_CLASS_MAGIC 0xdeadbeef
26
27 static struct ckrm_res_ctlr null_rcbs;
28
29 /*
30  * manages the class status
31  * there should be only one instance of this object for each class in the whole system  
32  */
33 struct ckrm_null_class {
34         struct ckrm_core_class *core;
35         struct ckrm_core_class *parent;
36         struct ckrm_shares shares;
37         spinlock_t cnt_lock;    // always grab parent's lock first and then child's
38         unsigned long magic;    //for debugging
39 };
40
41 /*
42  *  initialize a class object and its local queues
43  */
44 static void init_null_class(struct ckrm_null_class *cls,ckrm_shares_t* shares) 
45 {
46         cls->shares = *shares;
47         cls->cnt_lock = SPIN_LOCK_UNLOCKED;
48         cls->magic = CKRM_NULL_CLASS_MAGIC;
49 }
50
51 static inline void set_default_share(ckrm_shares_t *shares)
52 {
53         shares->my_guarantee     = 0;
54         shares->total_guarantee  = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
55         shares->unused_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
56         shares->my_limit         = CKRM_SHARE_DFLT_MAX_LIMIT;
57         shares->max_limit        = CKRM_SHARE_DFLT_MAX_LIMIT;
58         shares->cur_max_limit    = 0;
59 }
60
61 static inline int valid_null_class(struct ckrm_null_class * cls)
62 {
63         return (cls && cls->magic == CKRM_NULL_CLASS_MAGIC);
64 }
65
66
67 static struct ckrm_null_class * ckrm_get_null_class(struct ckrm_core_class *core)
68 {
69         struct ckrm_null_class * cls;
70         cls = ckrm_get_res_class(core, null_rcbs.resid, struct ckrm_null_class);
71         if (valid_null_class(cls))
72                 return cls;
73         else
74                 return NULL;
75 }
76
77
78 static struct ckrm_null_class default_null_class_obj;
79
80 static struct ckrm_null_class * get_default_null_class(void) {
81         return (&default_null_class_obj);
82 }
83
84
85 static void* ckrm_alloc_null_class(struct ckrm_core_class *core, struct ckrm_core_class *parent) 
86 {               
87         struct ckrm_null_class *cls;
88
89         if (! parent) /*root class*/
90                 cls =  get_default_null_class();
91         else
92                 cls = (struct ckrm_null_class *) kmalloc(sizeof(struct ckrm_null_class),GFP_ATOMIC);
93
94         if (cls) {
95                 ckrm_shares_t shares;           
96                 if ((! parent) && (core)) { 
97                         /*
98                          * the default class is already initialized
99                          * so only update the core structure
100                          */
101                         cls->core = core;                       
102                 } else {
103                         set_default_share(&shares);
104                         init_null_class(cls,&shares);
105                         cls->core = core;
106                         cls->parent = parent;                   
107                 }
108         } else
109                 printk(KERN_ERR"alloc_null_class failed\n");
110
111         return cls;
112 }               
113
114 /*
115  * hzheng: this is not a stable implementation
116  *         need to check race condition issue here
117  */             
118 static void ckrm_free_null_class(void *my_res) 
119 {                       
120         struct ckrm_null_class *cls = my_res, *parres, *childres;
121         ckrm_core_class_t *child = NULL;
122         int maxlimit;
123
124         if (!cls) 
125                 return;
126
127         /*the default class can't be freed*/
128         if (cls == get_default_null_class()) 
129                 return;
130
131         // Assuming there will be no children when this function is called
132         parres = ckrm_get_null_class(cls->parent);
133
134         // return child's limit/guarantee to parent node
135         spin_lock(&parres->cnt_lock);
136         child_guarantee_changed(&parres->shares, cls->shares.my_guarantee, 0);
137
138         // run thru parent's children and get the new max_limit of the parent
139         ckrm_lock_hier(parres->core);
140         maxlimit = 0;
141         while ((child = ckrm_get_next_child(parres->core, child)) != NULL) {
142                 childres = ckrm_get_null_class(child);
143                 if (maxlimit < childres->shares.my_limit) {
144                         maxlimit = childres->shares.my_limit;
145                 }
146         }
147         ckrm_unlock_hier(parres->core);
148         if (parres->shares.cur_max_limit < maxlimit) {
149                 parres->shares.cur_max_limit = maxlimit;
150         }
151
152         spin_unlock(&parres->cnt_lock);
153         kfree(cls);
154 }                               
155
156 /*
157  *  the system will adjust to the new share automatically  
158  */                     
159 static int ckrm_null_set_share(void *my_res, struct ckrm_shares *new_share) 
160 {       
161         struct ckrm_null_class *parres, *cls = my_res;
162         struct ckrm_shares *cur = &cls->shares, *par;
163         int rc = -EINVAL;
164
165         if (!cls)
166                 return rc;
167
168         if (cls->parent) {
169                 parres = ckrm_get_null_class(cls->parent);
170                 spin_lock(&parres->cnt_lock);
171                 spin_lock(&cls->cnt_lock);
172                 par = &parres->shares;
173         } else {
174                 spin_lock(&cls->cnt_lock);
175                 par = NULL;
176                 parres = NULL;
177         }
178
179         /*
180          * hzheng: CKRM_SHARE_DONTCARE should be handled
181          */
182         if (new_share->my_guarantee == CKRM_SHARE_DONTCARE)
183                 new_share->my_guarantee = 0;
184
185         rc = set_shares(new_share, cur, par);
186         if (cur->my_limit == CKRM_SHARE_DONTCARE)
187                 cur->my_limit = cur->max_limit;
188
189
190         spin_unlock(&cls->cnt_lock);
191         if (cls->parent) {
192                 spin_unlock(&parres->cnt_lock);
193         }
194
195         return rc;
196 }                                                       
197                         
198 static int ckrm_null_get_share(void *my_res,
199                               struct ckrm_shares *shares)
200 {                       
201         struct ckrm_null_class *cls = my_res;
202
203         if (!cls)
204                 return -EINVAL;
205         *shares = cls->shares;
206         return 0;
207 }                               
208
209 static int ckrm_null_get_stats(void *my_res, struct seq_file * sfile)
210 {
211         struct ckrm_null_class *cls = my_res;
212
213         if (!cls) 
214                 return -EINVAL;
215
216         seq_printf(sfile, "-------- Null Class Status Start---------\n");
217         seq_printf(sfile, "Share:\n\tgrt= %d limit= %d total_grt= %d max_limit= %d\n",
218                    cls->shares.my_guarantee,
219                    cls->shares.my_limit,
220                    cls->shares.total_guarantee,
221                    cls->shares.max_limit);
222         seq_printf(sfile, "\tunused_grt= %d cur_max_limit= %d\n",
223                    cls->shares.unused_guarantee,
224                    cls->shares.cur_max_limit);
225
226         seq_printf(sfile, "-------- Null Class Status END ---------\n");
227
228         return 0;
229 }
230
231 /*
232  * task will remain in the same null but on a different local runqueue
233  */
234 static void ckrm_null_change_class(void *task, void *old, void *new)
235 {               
236         /*sanity checking*/
237         if (!task || ! old || !new)
238                 return; 
239
240         /* hook to controller */
241 }                                                       
242
243 /*dummy function, not used*/
244 static int ckrm_null_show_config(void *my_res, struct seq_file *sfile)
245 {
246         struct ckrm_null_class *cls = my_res;
247
248         if (!cls) 
249                 return -EINVAL;
250
251         seq_printf(sfile, "cls=%s,parameter=somevalue\n","ckrm_null class");
252         return 0;
253 }
254
255 /*dummy function, not used*/
256 static int ckrm_null_set_config(void *my_res, const char *cfgstr)
257 {
258         struct ckrm_nullclass *cls = my_res;
259
260         if (!cls) 
261                 return -EINVAL;
262         printk(KERN_DEBUG "ckrm_null config='%s'\n",cfgstr);
263         return 0;
264 }
265         
266 static struct ckrm_res_ctlr null_rcbs = {
267         .res_name          = "null",
268         .res_hdepth        = 1,
269         .resid             = -1,
270         .res_alloc         = ckrm_alloc_null_class,
271         .res_free          = ckrm_free_null_class,
272         .set_share_values  = ckrm_null_set_share,
273         .get_share_values  = ckrm_null_get_share,
274         .get_stats         = ckrm_null_get_stats,
275         .show_config       = ckrm_null_show_config,
276         .set_config        = ckrm_null_set_config,
277         .change_resclass   = ckrm_null_change_class,
278 };
279
280 int __init init_ckrm_null_res(void)
281 {
282         struct ckrm_classtype *clstype;
283         int resid = null_rcbs.resid;
284
285         clstype = ckrm_find_classtype_by_name("taskclass");
286         if (clstype == NULL) {
287                 printk(KERN_INFO" Unknown ckrm classtype<taskclass>");
288                 return -ENOENT;
289         }
290
291         /* Initialize default class obj before registering with core */
292         ckrm_alloc_null_class(NULL,NULL);
293
294         if (resid == -1) { /*not registered */
295                 resid = ckrm_register_res_ctlr(clstype,&null_rcbs);
296                 printk(KERN_DEBUG "........init_ckrm_null_res , resid= %d\n",resid);
297         }
298         return 0;
299 }
300
301 void __exit exit_ckrm_null_res(void)
302 {
303         ckrm_unregister_res_ctlr(&null_rcbs);
304         null_rcbs.resid = -1;
305 }
306
307 module_init(init_ckrm_null_res)
308 module_exit(exit_ckrm_null_res)