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