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