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