278aec95becc0f2811859d7a01ce353b673275b5
[linux-2.6.git] / kernel / ckrm / ckrm.c
1 /* ckrm.c - Class-based Kernel Resource Management (CKRM)
2  *
3  * Copyright (C) Hubertus Franke, IBM Corp. 2003, 2004
4  *           (C) Shailabh Nagar,  IBM Corp. 2003, 2004
5  *           (C) Chandra Seetharaman,  IBM Corp. 2003
6  *           (C) Vivek Kashyap, IBM Corp. 2004
7  * 
8  * 
9  * Provides kernel API of CKRM for in-kernel,per-resource controllers 
10  * (one each for cpu, memory, io, network) and callbacks for 
11  * classification modules.
12  *
13  * Latest version, more details at http://ckrm.sf.net
14  * 
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 2 of the License, or
18  * (at your option) any later version.
19  *
20  */
21
22 /*
23  * Changes
24  *
25  * 28 Aug 2003
26  *        Created.
27  * 06 Nov 2003
28  *        Made modifications to suit the new RBCE module.
29  * 10 Nov 2003
30  *        Fixed a bug in fork and exit callbacks. Added callbacks_active and
31  *        surrounding logic. Added task paramter for all CE callbacks.
32  * 23 Mar 2004
33  *        moved to referenced counted class objects and correct locking
34  * 19 Apr 2004
35  *        Integrated ckrm hooks, classtypes, ...
36  *  
37  */
38
39 #include <linux/config.h>
40 #include <linux/init.h>
41 #include <linux/linkage.h>
42 #include <linux/kernel.h>
43 #include <linux/errno.h>
44 #include <asm/uaccess.h>
45 #include <linux/mm.h>
46 #include <asm/errno.h>
47 #include <linux/string.h>
48 #include <linux/list.h>
49 #include <linux/spinlock.h>
50 #include <linux/module.h>
51 #include <linux/ckrm_rc.h>
52 #include <linux/rcfs.h>
53 #include <net/sock.h>
54 #include <linux/ip.h>
55
56 rwlock_t ckrm_class_lock = RW_LOCK_UNLOCKED;    /* protects classlists */
57
58 struct rcfs_functions rcfs_fn;
59 EXPORT_SYMBOL_GPL(rcfs_fn);
60
61 int rcfs_engine_regd;           /* rcfs state needed by another module */
62 EXPORT_SYMBOL_GPL(rcfs_engine_regd);
63
64 int rcfs_mounted;
65 EXPORT_SYMBOL_GPL(rcfs_mounted);
66
67 /*
68  * Helper Functions
69  */
70
71 /*
72  * Return TRUE if the given resource is registered.
73  */
74 inline unsigned int is_res_regd(struct ckrm_classtype *clstype, int resid)
75 {
76         return ((resid >= 0) && (resid < clstype->max_resid) &&
77                 test_bit(resid, &clstype->bit_res_ctlrs)
78             );
79 }
80
81 /*
82  * Return TRUE if the given core class pointer is valid.
83  */
84 static struct ckrm_res_ctlr *ckrm_resctlr_lookup(struct ckrm_classtype *clstype,
85                                           const char *resname)
86 {
87         int resid = -1;
88
89         if (!clstype || !resname) {
90                 return NULL;
91         }
92         for (resid = 0; resid < clstype->max_resid; resid++) {
93                 if (test_bit(resid, &clstype->bit_res_ctlrs)) {
94                         struct ckrm_res_ctlr *rctrl = clstype->res_ctlrs[resid];
95                         if (!strncmp(resname, rctrl->res_name,
96                                      CKRM_MAX_RES_NAME))
97                                 return rctrl;
98                 }
99         }
100         return NULL;
101 }
102
103
104 /* given a classname return the class handle and its classtype*/
105 void *ckrm_classobj(const char *classname, int *classTypeID)
106 {
107         int i;
108
109         *classTypeID = -1;
110         if (!classname || !*classname) {
111                 return NULL;
112         }
113
114         read_lock(&ckrm_class_lock);
115         for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) {
116                 struct ckrm_classtype *ctype = ckrm_classtypes[i];
117                 struct ckrm_core_class *core;
118
119                 if (ctype == NULL)
120                         continue;
121                 list_for_each_entry(core, &ctype->classes, clslist) {
122                         if (core->name && !strcmp(core->name, classname)) {
123                                 // FIXME:   should grep reference..
124                                 read_unlock(&ckrm_class_lock);
125                                 *classTypeID = ctype->typeID;
126                                 return core;
127                         }
128                 }
129         }
130         read_unlock(&ckrm_class_lock);
131         return NULL;
132 }
133
134 EXPORT_SYMBOL_GPL(is_res_regd);
135 EXPORT_SYMBOL_GPL(ckrm_classobj);
136
137 /*
138  * Internal Functions/macros
139  */
140
141 static inline void set_callbacks_active(struct ckrm_classtype *ctype)
142 {
143         ctype->ce_cb_active = ((atomic_read(&ctype->ce_regd) > 0) &&
144                                (ctype->ce_callbacks.always_callback
145                                 || (ctype->num_classes > 1)));
146 }
147
148 int ckrm_validate_and_grab_core(struct ckrm_core_class *core)
149 {
150         int rc = 0;
151         read_lock(&ckrm_class_lock);
152         if (likely(ckrm_is_core_valid(core))) {
153                 ckrm_core_grab(core);
154                 rc = 1;
155         }
156         read_unlock(&ckrm_class_lock);
157         return rc;
158 }
159
160 /*
161  * Interfaces for classification engine
162  */
163
164 /*
165  * Registering a callback structure by the classification engine.
166  *
167  * Returns typeId of class on success -errno for failure.
168  */
169 int ckrm_register_engine(const char *typename, ckrm_eng_callback_t * ecbs)
170 {
171         struct ckrm_classtype *ctype;
172
173         ctype = ckrm_find_classtype_by_name(typename);
174         if (ctype == NULL)
175                 return (-ENOENT);
176
177         atomic_inc(&ctype->ce_regd);
178
179         /* another engine registered or trying to register ? */
180         if (atomic_read(&ctype->ce_regd) != 1) {
181                 atomic_dec(&ctype->ce_regd);
182                 return (-EBUSY);
183         }
184
185         /*
186          * One of the following must be set: 
187          * classify, class_delete (due to object reference) or 
188          * notify (case where notification supported but not classification)
189          * The function pointer must be set the momement the mask is non-null
190          */
191         if (!(((ecbs->classify) && (ecbs->class_delete)) || (ecbs->notify)) ||
192             (ecbs->c_interest && ecbs->classify == NULL) ||
193             (ecbs->n_interest && ecbs->notify == NULL)) {
194                 atomic_dec(&ctype->ce_regd);
195                 return (-EINVAL);
196         }
197
198         ctype->ce_callbacks = *ecbs;
199         set_callbacks_active(ctype);
200
201         if (ctype->ce_callbacks.class_add) {
202                 struct ckrm_core_class *core;
203
204                 read_lock(&ckrm_class_lock);
205                 list_for_each_entry(core, &ctype->classes, clslist) {
206                         (*ctype->ce_callbacks.class_add) (core->name, core,
207                                                           ctype->typeID);
208                 }
209                 read_unlock(&ckrm_class_lock);
210         }
211         return ctype->typeID;
212 }
213
214 /*
215  * Unregistering a callback structure by the classification engine.
216  *
217  * Returns 0 on success -errno for failure.
218  */
219 int ckrm_unregister_engine(const char *typename)
220 {
221         struct ckrm_classtype *ctype;
222
223         ctype = ckrm_find_classtype_by_name(typename);
224         if (ctype == NULL)
225                 return (-ENOENT);
226
227         ctype->ce_cb_active = 0;
228         if (atomic_read(&ctype->ce_nr_users) > 1) {
229                 /* Somebody is currently using the engine, cannot deregister. */
230                 return (-EAGAIN);
231         }
232         atomic_set(&ctype->ce_regd, 0);
233         memset(&ctype->ce_callbacks, 0, sizeof(ckrm_eng_callback_t));
234         return 0;
235 }
236
237 /*
238  * Interfaces to manipulate class (core or resource) hierarchies
239  */
240
241 static void
242 ckrm_add_child(struct ckrm_core_class *parent, struct ckrm_core_class *child)
243 {
244         struct ckrm_hnode *cnode = &child->hnode;
245
246         if (!ckrm_is_core_valid(child)) {
247                 printk(KERN_ERR "Invalid child %p given in ckrm_add_child\n",
248                        child);
249                 return;
250         }
251         class_lock(child);
252         INIT_LIST_HEAD(&cnode->children);
253         INIT_LIST_HEAD(&cnode->siblings);
254
255         if (parent) {
256                 struct ckrm_hnode *pnode;
257
258                 if (!ckrm_is_core_valid(parent)) {
259                         printk(KERN_ERR
260                                "Invalid parent %p given in ckrm_add_child\n",
261                                parent);
262                         parent = NULL;
263                 } else {
264                         pnode = &parent->hnode;
265                         write_lock(&parent->hnode_rwlock);
266                         list_add(&cnode->siblings, &pnode->children);
267                         write_unlock(&parent->hnode_rwlock);
268                 }
269         }
270         cnode->parent = parent;
271         class_unlock(child);
272         return;
273 }
274
275 static int ckrm_remove_child(struct ckrm_core_class *child)
276 {
277         struct ckrm_hnode *cnode, *pnode;
278         struct ckrm_core_class *parent;
279
280         if (!ckrm_is_core_valid(child)) {
281                 printk(KERN_ERR "Invalid child %p given"
282                                 " in ckrm_remove_child\n",
283                         child);
284                 return 0;
285         }
286
287         cnode = &child->hnode;
288         parent = cnode->parent;
289         if (!ckrm_is_core_valid(parent)) {
290                 printk(KERN_ERR "Invalid parent %p in ckrm_remove_child\n",
291                        parent);
292                 return 0;
293         }
294
295         pnode = &parent->hnode;
296
297         class_lock(child);
298         /* ensure that the node does not have children */
299         if (!list_empty(&cnode->children)) {
300                 class_unlock(child);
301                 return 0;
302         }
303         write_lock(&parent->hnode_rwlock);
304         list_del(&cnode->siblings);
305         write_unlock(&parent->hnode_rwlock);
306         cnode->parent = NULL;
307         class_unlock(child);
308         return 1;
309 }
310
311 void ckrm_lock_hier(struct ckrm_core_class *parent)
312 {
313         if (ckrm_is_core_valid(parent)) {
314                 read_lock(&parent->hnode_rwlock);
315         }
316 }
317
318 void ckrm_unlock_hier(struct ckrm_core_class *parent)
319 {
320         if (ckrm_is_core_valid(parent)) {
321                 read_unlock(&parent->hnode_rwlock);
322         }
323 }
324
325 /*
326  * hnode_rwlock of the parent core class must held in read mode.
327  * external callers should 've called ckrm_lock_hier before calling this
328  * function.
329  */
330 #define hnode_2_core(ptr) \
331 ((ptr)? container_of(ptr, struct ckrm_core_class, hnode) : NULL)
332
333 struct ckrm_core_class *ckrm_get_next_child(struct ckrm_core_class *parent,
334                                             struct ckrm_core_class *child)
335 {
336         struct list_head *cnode;
337         struct ckrm_hnode *next_cnode;
338         struct ckrm_core_class *next_childcore;
339
340         if (!ckrm_is_core_valid(parent)) {
341                 printk(KERN_ERR "Invalid parent %p in ckrm_get_next_child\n",
342                        parent);
343                 return NULL;
344         }
345         if (list_empty(&parent->hnode.children)) {
346                 return NULL;
347         }
348         if (child) {
349                 if (!ckrm_is_core_valid(child)) {
350                         printk(KERN_ERR
351                                "Invalid child %p in ckrm_get_next_child\n",
352                                child);
353                         return NULL;
354                 }
355                 cnode = child->hnode.siblings.next;
356         } else {
357                 cnode = parent->hnode.children.next;
358         }
359
360         if (cnode == &parent->hnode.children) { /* back at the anchor */
361                 return NULL;
362         }
363
364         next_cnode = container_of(cnode, struct ckrm_hnode, siblings);
365         next_childcore = hnode_2_core(next_cnode);
366
367         if (!ckrm_is_core_valid(next_childcore)) {
368                 printk(KERN_ERR
369                        "Invalid next child %p in ckrm_get_next_child\n",
370                        next_childcore);
371                 return NULL;
372         }
373         return next_childcore;
374 }
375
376 EXPORT_SYMBOL_GPL(ckrm_lock_hier);
377 EXPORT_SYMBOL_GPL(ckrm_unlock_hier);
378 EXPORT_SYMBOL_GPL(ckrm_get_next_child);
379
380 static void
381 ckrm_alloc_res_class(struct ckrm_core_class *core,
382                      struct ckrm_core_class *parent, int resid)
383 {
384
385         struct ckrm_classtype *clstype;
386         /* 
387          * Allocate a resource class only if the resource controller has
388          * registered with core and the engine requests for the class.
389          */
390         if (!ckrm_is_core_valid(core))
391                 return;
392         clstype = core->classtype;
393         core->res_class[resid] = NULL;
394
395         if (test_bit(resid, &clstype->bit_res_ctlrs)) {
396                 ckrm_res_ctlr_t *rcbs;
397
398                 atomic_inc(&clstype->nr_resusers[resid]);
399                 rcbs = clstype->res_ctlrs[resid];
400
401                 if (rcbs && rcbs->res_alloc) {
402                         core->res_class[resid] =
403                             (*rcbs->res_alloc) (core, parent);
404                         if (core->res_class[resid])
405                                 return;
406                         printk(KERN_ERR "Error creating res class\n");
407                 }
408                 atomic_dec(&clstype->nr_resusers[resid]);
409         }
410 }
411
412 /*
413  * Initialize a core class
414  *
415  */
416
417 #define CLS_DEBUG(fmt, args...) \
418 do { /* printk("%s: " fmt, __FUNCTION__ , ## args); */ } while (0)
419
420 int
421 ckrm_init_core_class(struct ckrm_classtype *clstype,
422                      struct ckrm_core_class *dcore,
423                      struct ckrm_core_class *parent, const char *name)
424 {
425         /* TODO:  Should replace name with dentry or add dentry? */
426         int i;
427
428         /* TODO:  How is this used in initialization? */
429         CLS_DEBUG("name %s => %p\n", name ? name : "default", dcore);
430         if ((dcore != clstype->default_class) && (!ckrm_is_core_valid(parent))){
431                 printk(KERN_DEBUG "error not a valid parent %p\n", parent);
432                 return -EINVAL;
433         }
434         dcore->classtype = clstype;
435         dcore->magic = CKRM_CORE_MAGIC;
436         dcore->name = name;
437         dcore->class_lock = SPIN_LOCK_UNLOCKED;
438         dcore->hnode_rwlock = RW_LOCK_UNLOCKED;
439         dcore->delayed = 0;
440
441         atomic_set(&dcore->refcnt, 0);
442         write_lock(&ckrm_class_lock);
443
444         INIT_LIST_HEAD(&dcore->objlist);
445         list_add_tail(&dcore->clslist, &clstype->classes);
446
447         clstype->num_classes++;
448         set_callbacks_active(clstype);
449
450         write_unlock(&ckrm_class_lock);
451         ckrm_add_child(parent, dcore);
452
453         for (i = 0; i < clstype->max_resid; i++)
454                 ckrm_alloc_res_class(dcore, parent, i);
455
456         /* fix for race condition seen in stress with numtasks */
457         if (parent)
458                 ckrm_core_grab(parent);
459
460         ckrm_core_grab(dcore);
461         return 0;
462 }
463
464 static void ckrm_free_res_class(struct ckrm_core_class *core, int resid)
465 {
466         /* 
467          * Free a resource class only if the resource controller has
468          * registered with core 
469          */
470         if (core->res_class[resid]) {
471                 ckrm_res_ctlr_t *rcbs;
472                 struct ckrm_classtype *clstype = core->classtype;
473
474                 atomic_inc(&clstype->nr_resusers[resid]);
475                 rcbs = clstype->res_ctlrs[resid];
476
477                 if (rcbs->res_free) {
478                         (*rcbs->res_free) (core->res_class[resid]);
479                         // compensate inc in alloc
480                         atomic_dec(&clstype->nr_resusers[resid]); 
481                 }
482                 atomic_dec(&clstype->nr_resusers[resid]);
483         }
484         core->res_class[resid] = NULL;
485 }
486
487 /*
488  * Free a core class 
489  *   requires that all tasks were previously reassigned to another class
490  *
491  * Returns 0 on success -errno on failure.
492  */
493
494 void ckrm_free_core_class(struct ckrm_core_class *core)
495 {
496         int i;
497         struct ckrm_classtype *clstype = core->classtype;
498         struct ckrm_core_class *parent = core->hnode.parent;
499
500         CLS_DEBUG("core=%p:%s parent=%p:%s\n", core, core->name, parent,
501                   parent->name);
502         if (core->delayed) {
503                 /* this core was marked as late */
504                 printk(KERN_DEBUG "class <%s> finally deleted %lu\n", core->name, jiffies);
505         }
506         if (ckrm_remove_child(core) == 0) {
507                 printk(KERN_DEBUG "Core class removal failed. Chilren present\n");
508         }
509         for (i = 0; i < clstype->max_resid; i++) {
510                 ckrm_free_res_class(core, i);
511         }
512
513         write_lock(&ckrm_class_lock);
514         /* Clear the magic, so we would know if this core is reused. */
515         core->magic = 0;
516 #if 0                           /* Dynamic not yet enabled */
517         core->res_class = NULL;
518 #endif
519         /* Remove this core class from its linked list. */
520         list_del(&core->clslist);
521         clstype->num_classes--;
522         set_callbacks_active(clstype);
523         write_unlock(&ckrm_class_lock);
524
525         /* fix for race condition seen in stress with numtasks */
526         if (parent)
527                 ckrm_core_drop(parent);
528
529         kfree(core);
530 }
531
532 int ckrm_release_core_class(struct ckrm_core_class *core)
533 {
534         if (!ckrm_is_core_valid(core)) {
535                 // Invalid core
536                 return (-EINVAL);
537         }
538
539         if (core == core->classtype->default_class)
540                 return 0;
541
542         /* need to make sure that the classgot really dropped */
543         if (atomic_read(&core->refcnt) != 1) {
544                 CLS_DEBUG("class <%s> deletion delayed refcnt=%d jif=%ld\n",
545                           core->name, atomic_read(&core->refcnt), jiffies);
546                 core->delayed = 1;      /* just so we have a ref point */
547         }
548         ckrm_core_drop(core);
549         return 0;
550 }
551
552 /*
553  * Interfaces for the resource controller
554  */
555 /*
556  * Registering a callback structure by the resource controller.
557  *
558  * Returns the resource id(0 or +ve) on success, -errno for failure.
559  */
560 static int
561 ckrm_register_res_ctlr_intern(struct ckrm_classtype *clstype,
562                               ckrm_res_ctlr_t * rcbs)
563 {
564         int resid, ret, i;
565
566         if (!rcbs)
567                 return -EINVAL;
568
569         resid = rcbs->resid;
570
571         spin_lock(&clstype->res_ctlrs_lock);
572         printk(KERN_WARNING "resid is %d name is %s %s\n",
573                resid, rcbs->res_name, clstype->res_ctlrs[resid]->res_name);
574         if (resid >= 0) {
575                 if ((resid < CKRM_MAX_RES_CTLRS)
576                     && (clstype->res_ctlrs[resid] == NULL)) {
577                         clstype->res_ctlrs[resid] = rcbs;
578                         atomic_set(&clstype->nr_resusers[resid], 0);
579                         set_bit(resid, &clstype->bit_res_ctlrs);
580                         ret = resid;
581                         if (resid >= clstype->max_resid) {
582                                 clstype->max_resid = resid + 1;
583                         }
584                 } else {
585                         ret = -EBUSY;
586                 }
587                 spin_unlock(&clstype->res_ctlrs_lock);
588                 return ret;
589         }
590         for (i = clstype->resid_reserved; i < clstype->max_res_ctlrs; i++) {
591                 if (clstype->res_ctlrs[i] == NULL) {
592                         clstype->res_ctlrs[i] = rcbs;
593                         rcbs->resid = i;
594                         atomic_set(&clstype->nr_resusers[i], 0);
595                         set_bit(i, &clstype->bit_res_ctlrs);
596                         if (i >= clstype->max_resid) {
597                                 clstype->max_resid = i + 1;
598                         }
599                         spin_unlock(&clstype->res_ctlrs_lock);
600                         return i;
601                 }
602         }
603         spin_unlock(&clstype->res_ctlrs_lock);
604         return (-ENOMEM);
605 }
606
607 int
608 ckrm_register_res_ctlr(struct ckrm_classtype *clstype, ckrm_res_ctlr_t * rcbs)
609 {
610         struct ckrm_core_class *core;
611         int resid;
612
613         resid = ckrm_register_res_ctlr_intern(clstype, rcbs);
614
615         if (resid >= 0) {
616                 /* run through all classes and create the resource class 
617                  * object and if necessary "initialize" class in context 
618                  * of this resource 
619                  */
620                 read_lock(&ckrm_class_lock);
621                 list_for_each_entry(core, &clstype->classes, clslist) {
622                         printk(KERN_INFO "CKRM .. create res clsobj for resouce <%s>"
623                                "class <%s> par=%p\n", rcbs->res_name, 
624                                core->name, core->hnode.parent);
625                         ckrm_alloc_res_class(core, core->hnode.parent, resid);
626
627                         if (clstype->add_resctrl) { 
628                                 /* FIXME: this should be mandatory */
629                                 (*clstype->add_resctrl) (core, resid);
630                         }
631                 }
632                 read_unlock(&ckrm_class_lock);
633         }
634         return resid;
635 }
636
637 /*
638  * Unregistering a callback structure by the resource controller.
639  *
640  * Returns 0 on success -errno for failure.
641  */
642 int ckrm_unregister_res_ctlr(struct ckrm_res_ctlr *rcbs)
643 {
644         struct ckrm_classtype *clstype = rcbs->classtype;
645         struct ckrm_core_class *core = NULL;
646         int resid = rcbs->resid;
647
648         if ((clstype == NULL) || (resid < 0)) {
649                 return -EINVAL;
650         }
651         /* TODO: probably need to also call deregistration function */
652
653         read_lock(&ckrm_class_lock);
654         /* free up this resource from all the classes */
655         list_for_each_entry(core, &clstype->classes, clslist) {
656                 ckrm_free_res_class(core, resid);
657         }
658         read_unlock(&ckrm_class_lock);
659
660         if (atomic_read(&clstype->nr_resusers[resid])) {
661                 return -EBUSY;
662         }
663
664         spin_lock(&clstype->res_ctlrs_lock);
665         clstype->res_ctlrs[resid] = NULL;
666         clear_bit(resid, &clstype->bit_res_ctlrs);
667         clstype->max_resid = fls(clstype->bit_res_ctlrs);
668         rcbs->resid = -1;
669         spin_unlock(&clstype->res_ctlrs_lock);
670
671         return 0;
672 }
673
674 /*
675  * Class Type Registration
676  */
677
678 /* TODO: What locking is needed here?*/
679
680 struct ckrm_classtype *ckrm_classtypes[CKRM_MAX_CLASSTYPES];
681 EXPORT_SYMBOL_GPL(ckrm_classtypes);     
682
683 int ckrm_register_classtype(struct ckrm_classtype *clstype)
684 {
685         int tid = clstype->typeID;
686
687         if (tid != -1) {
688                 if ((tid < 0) || (tid > CKRM_MAX_CLASSTYPES)
689                     || (ckrm_classtypes[tid]))
690                         return -EINVAL;
691         } else {
692                 int i;
693                 for (i = CKRM_RESV_CLASSTYPES; i < CKRM_MAX_CLASSTYPES; i++) {
694                         if (ckrm_classtypes[i] == NULL) {
695                                 tid = i;
696                                 break;
697                         }
698                 }
699         }
700         if (tid == -1)
701                 return -EBUSY;
702         clstype->typeID = tid;
703         ckrm_classtypes[tid] = clstype;
704
705         /* TODO: Need to call the callbacks of the RCFS client */
706         if (rcfs_fn.register_classtype) {
707                 (*rcfs_fn.register_classtype) (clstype);
708                 /* No error return for now. */
709         }
710         return tid;
711 }
712
713 int ckrm_unregister_classtype(struct ckrm_classtype *clstype)
714 {
715         int tid = clstype->typeID;
716
717         if ((tid < 0) || (tid > CKRM_MAX_CLASSTYPES)
718             || (ckrm_classtypes[tid] != clstype))
719                 return -EINVAL;
720
721         if (rcfs_fn.deregister_classtype) {
722                 (*rcfs_fn.deregister_classtype) (clstype);
723                 // No error return for now
724         }
725
726         ckrm_classtypes[tid] = NULL;
727         clstype->typeID = -1;
728         return 0;
729 }
730
731 struct ckrm_classtype *ckrm_find_classtype_by_name(const char *name)
732 {
733         int i;
734         for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) {
735                 struct ckrm_classtype *ctype = ckrm_classtypes[i];
736                 if (ctype && !strncmp(ctype->name, name, CKRM_MAX_TYPENAME_LEN))
737                         return ctype;
738         }
739         return NULL;
740 }
741
742 /*
743  *   Generic Functions that can be used as default functions 
744  *   in almost all classtypes
745  *     (a) function iterator over all resource classes of a class
746  *     (b) function invoker on a named resource
747  */
748
749 int ckrm_class_show_shares(struct ckrm_core_class *core, struct seq_file *seq)
750 {
751         int i;
752         struct ckrm_res_ctlr *rcbs;
753         struct ckrm_classtype *clstype = core->classtype;
754         struct ckrm_shares shares;
755
756         for (i = 0; i < clstype->max_resid; i++) {
757                 atomic_inc(&clstype->nr_resusers[i]);
758                 rcbs = clstype->res_ctlrs[i];
759                 if (rcbs && rcbs->get_share_values) {
760                         (*rcbs->get_share_values) (core->res_class[i], &shares);
761                         seq_printf(seq,"res=%s,guarantee=%d,limit=%d,"
762                                    "total_guarantee=%d,max_limit=%d\n",
763                                    rcbs->res_name, shares.my_guarantee,
764                                    shares.my_limit, shares.total_guarantee,
765                                    shares.max_limit);
766                 }
767                 atomic_dec(&clstype->nr_resusers[i]);
768         }
769         return 0;
770 }
771
772 int ckrm_class_show_stats(struct ckrm_core_class *core, struct seq_file *seq)
773 {
774         int i;
775         struct ckrm_res_ctlr *rcbs;
776         struct ckrm_classtype *clstype = core->classtype;
777
778         for (i = 0; i < clstype->max_resid; i++) {
779                 atomic_inc(&clstype->nr_resusers[i]);
780                 rcbs = clstype->res_ctlrs[i];
781                 if (rcbs && rcbs->get_stats)
782                         (*rcbs->get_stats) (core->res_class[i], seq);
783                 atomic_dec(&clstype->nr_resusers[i]);
784         }
785         return 0;
786 }
787
788 int ckrm_class_show_config(struct ckrm_core_class *core, struct seq_file *seq)
789 {
790         int i;
791         struct ckrm_res_ctlr *rcbs;
792         struct ckrm_classtype *clstype = core->classtype;
793
794         for (i = 0; i < clstype->max_resid; i++) {
795                 atomic_inc(&clstype->nr_resusers[i]);
796                 rcbs = clstype->res_ctlrs[i];
797                 if (rcbs && rcbs->show_config)
798                         (*rcbs->show_config) (core->res_class[i], seq);
799                 atomic_dec(&clstype->nr_resusers[i]);
800         }
801         return 0;
802 }
803
804 int ckrm_class_set_config(struct ckrm_core_class *core, const char *resname,
805                           const char *cfgstr)
806 {
807         struct ckrm_classtype *clstype = core->classtype;
808         struct ckrm_res_ctlr *rcbs = ckrm_resctlr_lookup(clstype, resname);
809         int rc;
810
811         if (rcbs == NULL || rcbs->set_config == NULL)
812                 return -EINVAL;
813         rc = (*rcbs->set_config) (core->res_class[rcbs->resid], cfgstr);
814         return rc;
815 }
816
817 #define legalshare(a)   \
818          ( ((a) >=0) \
819            || ((a) == CKRM_SHARE_UNCHANGED) \
820            || ((a) == CKRM_SHARE_DONTCARE) )
821
822 int ckrm_class_set_shares(struct ckrm_core_class *core, const char *resname,
823                           struct ckrm_shares *shares)
824 {
825         struct ckrm_classtype *clstype = core->classtype;
826         struct ckrm_res_ctlr *rcbs;
827         int rc;
828
829         /* Check for legal values */
830         if (!legalshare(shares->my_guarantee) || !legalshare(shares->my_limit)
831             || !legalshare(shares->total_guarantee)
832             || !legalshare(shares->max_limit))
833                 return -EINVAL;
834
835         rcbs = ckrm_resctlr_lookup(clstype, resname);
836         if (rcbs == NULL || rcbs->set_share_values == NULL)
837                 return -EINVAL;
838         rc = (*rcbs->set_share_values) (core->res_class[rcbs->resid], shares);
839         return rc;
840 }
841
842 int ckrm_class_reset_stats(struct ckrm_core_class *core, const char *resname,
843                            const char *unused)
844 {
845         struct ckrm_classtype *clstype = core->classtype;
846         struct ckrm_res_ctlr *rcbs = ckrm_resctlr_lookup(clstype, resname);
847         int rc;
848
849         if (rcbs == NULL || rcbs->reset_stats == NULL)
850                 return -EINVAL;
851         rc = (*rcbs->reset_stats) (core->res_class[rcbs->resid]);
852         return rc;
853 }
854
855 /*
856  * Initialization
857  */
858
859 void ckrm_cb_newtask(struct task_struct *tsk)
860 {
861         tsk->ce_data = NULL;
862         spin_lock_init(&tsk->ckrm_tsklock);
863         ckrm_invoke_event_cb_chain(CKRM_EVENT_NEWTASK, tsk);
864 }
865
866 void ckrm_cb_exit(struct task_struct *tsk)
867 {
868         ckrm_invoke_event_cb_chain(CKRM_EVENT_EXIT, tsk);
869         tsk->ce_data = NULL;
870 }
871
872 void __init ckrm_init(void)
873 {
874         printk(KERN_DEBUG "CKRM Initialization\n");
875
876         // prepare init_task and then rely on inheritance of properties
877         ckrm_cb_newtask(&init_task);
878
879         // register/initialize the Metatypes
880
881 #ifdef CONFIG_CKRM_TYPE_TASKCLASS
882         {
883                 extern void ckrm_meta_init_taskclass(void);
884                 ckrm_meta_init_taskclass();
885         }
886 #endif
887 #ifdef CONFIG_CKRM_TYPE_SOCKETCLASS
888         {
889                 extern void ckrm_meta_init_sockclass(void);
890                 ckrm_meta_init_sockclass();
891         }
892 #endif
893         printk("CKRM Initialization done\n");
894 }
895
896 EXPORT_SYMBOL_GPL(ckrm_register_engine);
897 EXPORT_SYMBOL_GPL(ckrm_unregister_engine);
898
899 EXPORT_SYMBOL_GPL(ckrm_register_res_ctlr);
900 EXPORT_SYMBOL_GPL(ckrm_unregister_res_ctlr);
901
902 EXPORT_SYMBOL_GPL(ckrm_init_core_class);
903 EXPORT_SYMBOL_GPL(ckrm_free_core_class);
904 EXPORT_SYMBOL_GPL(ckrm_release_core_class);
905
906 EXPORT_SYMBOL_GPL(ckrm_register_classtype);
907 EXPORT_SYMBOL_GPL(ckrm_unregister_classtype);
908 EXPORT_SYMBOL_GPL(ckrm_find_classtype_by_name);
909
910 EXPORT_SYMBOL_GPL(ckrm_core_grab);
911 EXPORT_SYMBOL_GPL(ckrm_core_drop);
912 EXPORT_SYMBOL_GPL(ckrm_is_core_valid);
913 EXPORT_SYMBOL_GPL(ckrm_validate_and_grab_core);
914
915 EXPORT_SYMBOL_GPL(ckrm_register_event_set);
916 EXPORT_SYMBOL_GPL(ckrm_unregister_event_set);
917 EXPORT_SYMBOL_GPL(ckrm_register_event_cb);
918 EXPORT_SYMBOL_GPL(ckrm_unregister_event_cb);
919
920 EXPORT_SYMBOL_GPL(ckrm_class_show_stats);
921 EXPORT_SYMBOL_GPL(ckrm_class_show_config);
922 EXPORT_SYMBOL_GPL(ckrm_class_show_shares);
923
924 EXPORT_SYMBOL_GPL(ckrm_class_set_config);
925 EXPORT_SYMBOL_GPL(ckrm_class_set_shares);
926
927 EXPORT_SYMBOL_GPL(ckrm_class_reset_stats);