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