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