ckrm_E16rc1 cpu controller version 8.2
[linux-2.6.git] / kernel / ckrm / ckrm_listenaq.c
1 /* ckrm_socketaq.c - accept queue resource controller
2  *
3  * Copyright (C) Vivek Kashyap,      IBM Corp. 2004
4  * 
5  * Latest version, more details at http://ckrm.sf.net
6  * 
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  */
13
14 /* Changes
15  * Initial version
16  */
17
18 /* Code Description: TBD
19  *
20  */
21
22 #include <linux/module.h>
23 #include <linux/init.h>
24 #include <linux/slab.h>
25 #include <asm/errno.h>
26 #include <linux/list.h>
27 #include <linux/spinlock.h>
28 #include <linux/ckrm.h>
29 #include <linux/ckrm_rc.h>
30 #include <net/tcp.h>
31
32 #include <linux/ckrm_net.h>
33
34 #define hnode_2_core(ptr) \
35         ((ptr) ? container_of(ptr, struct ckrm_core_class, hnode) : NULL)
36
37 #define CKRM_SAQ_MAX_DEPTH      3       // 0 => /rcfs
38                                   // 1 => socket_aq
39                                   // 2 => socket_aq/listen_class
40                                   // 3 => socket_aq/listen_class/accept_queues
41                                   // 4 => Not allowed
42
43 typedef struct ckrm_laq_res {
44         spinlock_t reslock;
45         atomic_t refcnt;
46         struct ckrm_shares shares;
47         struct ckrm_core_class *core;
48         struct ckrm_core_class *pcore;
49         int my_depth;
50         int my_id;
51         unsigned int min_ratio;
52 } ckrm_laq_res_t;
53
54 static int my_resid = -1;
55
56 extern struct ckrm_core_class *rcfs_create_under_netroot(char *, int, int);
57 extern struct ckrm_core_class *rcfs_make_core(struct dentry *,
58                                               struct ckrm_core_class *);
59
60 void laq_res_hold(struct ckrm_laq_res *res)
61 {
62         atomic_inc(&res->refcnt);
63         return;
64 }
65
66 void laq_res_put(struct ckrm_laq_res *res)
67 {
68         if (atomic_dec_and_test(&res->refcnt))
69                 kfree(res);
70         return;
71 }
72
73 /* Initialize rescls values
74  */
75 static void laq_res_initcls(void *my_res)
76 {
77         ckrm_laq_res_t *res = my_res;
78
79         res->shares.my_guarantee = CKRM_SHARE_DONTCARE;
80         res->shares.my_limit = CKRM_SHARE_DONTCARE;
81         res->shares.total_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
82         res->shares.max_limit = CKRM_SHARE_DFLT_MAX_LIMIT;
83         res->shares.unused_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
84         res->shares.cur_max_limit = 0;
85 }
86
87 static int atoi(char *s)
88 {
89         int k = 0;
90         while (*s)
91                 k = *s++ - '0' + (k * 10);
92         return k;
93 }
94
95 static char *laq_get_name(struct ckrm_core_class *c)
96 {
97         char *p = (char *)c->name;
98
99         while (*p)
100                 p++;
101         while (*p != '/' && p != c->name)
102                 p--;
103
104         return ++p;
105 }
106
107 static void *laq_res_alloc(struct ckrm_core_class *core,
108                            struct ckrm_core_class *parent)
109 {
110         ckrm_laq_res_t *res, *pres;
111         int pdepth;
112
113         if (parent)
114                 pres = ckrm_get_res_class(parent, my_resid, ckrm_laq_res_t);
115         else
116                 pres = NULL;
117
118         if (core == core->classtype->default_class)
119                 pdepth = 1;
120         else {
121                 if (!parent)
122                         return NULL;
123                 pdepth = 1 + pres->my_depth;
124         }
125
126         res = kmalloc(sizeof(ckrm_laq_res_t), GFP_ATOMIC);
127         if (res) {
128                 memset(res, 0, sizeof(res));
129                 spin_lock_init(&res->reslock);
130                 laq_res_hold(res);
131                 res->my_depth = pdepth;
132                 if (pdepth == 2)        // listen class
133                         res->my_id = 0;
134                 else if (pdepth == 3)
135                         res->my_id = atoi(laq_get_name(core));
136                 res->core = core;
137                 res->pcore = parent;
138
139                 // rescls in place, now initialize contents other than 
140                 // hierarchy pointers
141                 laq_res_initcls(res);   // acts as initialising value
142         }
143
144         return res;
145 }
146
147 static void laq_res_free(void *my_res)
148 {
149         ckrm_laq_res_t *res = (ckrm_laq_res_t *) my_res;
150         ckrm_laq_res_t *parent;
151
152         if (!res)
153                 return;
154
155         if (res->my_depth != 3) {
156                 kfree(res);
157                 return;
158         }
159
160         parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t);
161         if (!parent)            // Should never happen
162                 return;
163
164         spin_lock(&parent->reslock);
165         spin_lock(&res->reslock);
166
167         // return child's guarantee to parent node
168         // Limits have no meaning for accept queue control
169         child_guarantee_changed(&parent->shares, res->shares.my_guarantee, 0);
170
171         spin_unlock(&res->reslock);
172         laq_res_put(res);
173         spin_unlock(&parent->reslock);
174         return;
175 }
176
177 /**************************************************************************
178  *                      SHARES                                          ***
179  **************************************************************************/
180
181 void laq_set_aq_value(struct ckrm_net_struct *ns, unsigned int *aq_ratio)
182 {
183         int i;
184         struct tcp_opt *tp;
185
186         tp = tcp_sk(ns->ns_sk);
187         for (i = 0; i < NUM_ACCEPT_QUEUES; i++)
188                 tp->acceptq[i].aq_ratio = aq_ratio[i];
189         return;
190 }
191 void laq_set_aq_values(ckrm_laq_res_t * parent, unsigned int *aq_ratio)
192 {
193
194         struct ckrm_net_struct *ns;
195         struct ckrm_core_class *core = parent->core;
196
197         class_lock(core);
198         list_for_each_entry(ns, &core->objlist, ckrm_link) {
199                 laq_set_aq_value(ns, aq_ratio);
200         }
201         class_unlock(core);
202         return;
203 }
204
205 static void calculate_aq_ratios(ckrm_laq_res_t * res, unsigned int *aq_ratio)
206 {
207         struct ckrm_hnode *chnode;
208         ckrm_laq_res_t *child;
209         unsigned int min;
210         int i;
211
212         min = aq_ratio[0] = (unsigned int)res->shares.unused_guarantee;
213
214         list_for_each_entry(chnode, &res->core->hnode.children, siblings) {
215                 child = hnode_2_core(chnode)->res_class[my_resid];
216
217                 aq_ratio[child->my_id] =
218                     (unsigned int)child->shares.my_guarantee;
219                 if (aq_ratio[child->my_id] == CKRM_SHARE_DONTCARE)
220                         aq_ratio[child->my_id] = 0;
221                 if (aq_ratio[child->my_id] &&
222                     ((unsigned int)aq_ratio[child->my_id] < min))
223                         min = (unsigned int)child->shares.my_guarantee;
224         }
225
226         if (min == 0) {
227                 min = 1;
228                 // default takes all if nothing specified
229                 aq_ratio[0] = 1;        
230         }
231         res->min_ratio = min;
232
233         for (i = 0; i < NUM_ACCEPT_QUEUES; i++)
234                 aq_ratio[i] = aq_ratio[i] / min;
235 }
236
237 static int laq_set_share_values(void *my_res, struct ckrm_shares *shares)
238 {
239         ckrm_laq_res_t *res = my_res;
240         ckrm_laq_res_t *parent;
241         unsigned int aq_ratio[NUM_ACCEPT_QUEUES];
242         int rc = 0;
243
244         if (!res)
245                 return -EINVAL;
246
247         if (!res->pcore) {
248                 // something is badly wrong
249                 printk(KERN_ERR "socketaq internal inconsistency\n");
250                 return -EBADF;
251         }
252
253         parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t);
254         if (!parent)            // socket_class does not have a share interface
255                 return -EINVAL;
256
257         // Ensure that we ignore limit values
258         shares->my_limit = CKRM_SHARE_DONTCARE;
259         shares->max_limit = CKRM_SHARE_UNCHANGED;
260
261         if (res->my_depth == 0) {
262                 printk(KERN_ERR "socketaq bad entry\n");
263                 return -EBADF;
264         } else if (res->my_depth == 1) {
265                 // can't be written to. This is an internal default.
266                 return -EINVAL;
267         } else if (res->my_depth == 2) {
268                 //nothin to inherit
269                 if (!shares->total_guarantee) {
270                         return -EINVAL;
271                 }
272                 parent = res;
273                 shares->my_guarantee = CKRM_SHARE_DONTCARE;
274         } else if (res->my_depth == 3) {
275                 // accept queue itself. 
276                 shares->total_guarantee = CKRM_SHARE_UNCHANGED;
277         }
278
279         ckrm_lock_hier(parent->pcore);
280         spin_lock(&parent->reslock);
281         rc = set_shares(shares, &res->shares,
282                         (parent == res) ? NULL : &parent->shares);
283         if (rc) {
284                 spin_unlock(&res->reslock);
285                 ckrm_unlock_hier(res->pcore);
286                 return rc;
287         }
288         calculate_aq_ratios(parent, aq_ratio);
289         laq_set_aq_values(parent, aq_ratio);
290         spin_unlock(&parent->reslock);
291         ckrm_unlock_hier(parent->pcore);
292
293         return rc;
294 }
295
296 static int laq_get_share_values(void *my_res, struct ckrm_shares *shares)
297 {
298         ckrm_laq_res_t *res = my_res;
299
300         if (!res)
301                 return -EINVAL;
302         *shares = res->shares;
303         return 0;
304 }
305
306 /**************************************************************************
307  *                      STATS                                           ***
308  **************************************************************************/
309
310 void
311 laq_print_aq_stats(struct seq_file *sfile, struct tcp_acceptq_info *taq, int i)
312 {
313         seq_printf(sfile, "Class %d connections:\n\taccepted: %u\n\t"
314                    "queued: %u\n\twait_time: %u\n",
315                    i, taq->acceptq_count, taq->acceptq_qcount,
316                    jiffies_to_msecs(taq->acceptq_wait_time));
317
318         if (i)
319                 return;
320
321         for (i = 1; i < NUM_ACCEPT_QUEUES; i++) {
322                 taq[0].acceptq_wait_time += taq[i].acceptq_wait_time;
323                 taq[0].acceptq_qcount += taq[i].acceptq_qcount;
324                 taq[0].acceptq_count += taq[i].acceptq_count;
325         }
326
327         seq_printf(sfile, "Totals :\n\taccepted: %u\n\t"
328                    "queued: %u\n\twait_time: %u\n",
329                    taq->acceptq_count, taq->acceptq_qcount,
330                    jiffies_to_msecs(taq->acceptq_wait_time));
331
332         return;
333 }
334
335 void
336 laq_get_aq_stats(ckrm_laq_res_t * pres, ckrm_laq_res_t * mres,
337                  struct tcp_acceptq_info *taq)
338 {
339         struct ckrm_net_struct *ns;
340         struct ckrm_core_class *core = pres->core;
341         struct tcp_opt *tp;
342         int a = mres->my_id;
343         int z;
344
345         if (a == 0)
346                 z = NUM_ACCEPT_QUEUES;
347         else
348                 z = a + 1;
349
350         // XXX Instead of holding a  class_lock introduce a rw
351         // lock to be write locked by listen callbacks and read locked here.
352         // - VK
353         class_lock(pres->core);
354         list_for_each_entry(ns, &core->objlist, ckrm_link) {
355                 tp = tcp_sk(ns->ns_sk);
356                 for (; a < z; a++) {
357                         taq->acceptq_wait_time += tp->acceptq[a].aq_wait_time;
358                         taq->acceptq_qcount += tp->acceptq[a].aq_qcount;
359                         taq->acceptq_count += tp->acceptq[a].aq_count;
360                         taq++;
361                 }
362         }
363         class_unlock(pres->core);
364 }
365
366 static int laq_get_stats(void *my_res, struct seq_file *sfile)
367 {
368         ckrm_laq_res_t *res = my_res;
369         ckrm_laq_res_t *parent;
370         struct tcp_acceptq_info taq[NUM_ACCEPT_QUEUES];
371         int rc = 0;
372
373         if (!res)
374                 return -EINVAL;
375
376         if (!res->pcore) {
377                 // something is badly wrong
378                 printk(KERN_ERR "socketaq internal inconsistency\n");
379                 return -EBADF;
380         }
381
382         parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t);
383         if (!parent) {          // socket_class does not have a stat interface
384                 printk(KERN_ERR "socketaq internal fs inconsistency\n");
385                 return -EINVAL;
386         }
387
388         memset(taq, 0, sizeof(struct tcp_acceptq_info) * NUM_ACCEPT_QUEUES);
389
390         switch (res->my_depth) {
391
392         default:
393         case 0:
394                 printk(KERN_ERR "socket class bad entry\n");
395                 rc = -EBADF;
396                 break;
397
398         case 1:         // can't be read from. this is internal default.
399                 // return -EINVAL
400                 rc = -EINVAL;
401                 break;
402
403         case 2:         // return the default and total
404                 ckrm_lock_hier(res->core);      // block any deletes
405                 laq_get_aq_stats(res, res, &taq[0]);
406                 laq_print_aq_stats(sfile, &taq[0], 0);
407                 ckrm_unlock_hier(res->core);    // block any deletes
408                 break;
409
410         case 3:
411                 ckrm_lock_hier(parent->core);   // block any deletes
412                 laq_get_aq_stats(parent, res, &taq[res->my_id]);
413                 laq_print_aq_stats(sfile, &taq[res->my_id], res->my_id);
414                 ckrm_unlock_hier(parent->core); // block any deletes
415                 break;
416         }
417
418         return rc;
419 }
420
421 /*
422  * The network connection is reclassified to this class. Update its shares.
423  * The socket lock is held. 
424  */
425 static void laq_change_resclass(void *n, void *old, void *r)
426 {
427         struct ckrm_net_struct *ns = (struct ckrm_net_struct *)n;
428         struct ckrm_laq_res *res = (struct ckrm_laq_res *)r;
429         unsigned int aq_ratio[NUM_ACCEPT_QUEUES];
430
431         if (res->my_depth != 2)
432                 return;
433
434         // a change to my_depth == 3 ie. the accept classes cannot happen.
435         // there is no target file
436         if (res->my_depth == 2) {       // it is one of the socket classes
437                 ckrm_lock_hier(res->pcore);
438                 // share rule: hold parent resource lock. then self.
439                 // However, since my_depth == 1 is a generic class it is not
440                 // needed here. Self lock is enough.
441                 spin_lock(&res->reslock);
442                 calculate_aq_ratios(res, aq_ratio);
443                 class_lock(res->pcore);
444                 laq_set_aq_value(ns, aq_ratio);
445                 class_unlock(res->pcore);
446                 spin_unlock(&res->reslock);
447                 ckrm_unlock_hier(res->pcore);
448         }
449
450         return;
451 }
452
453 struct ckrm_res_ctlr laq_rcbs = {
454         .res_name = "laq",
455         .resid = -1,            // dynamically assigned
456         .res_alloc = laq_res_alloc,
457         .res_free = laq_res_free,
458         .set_share_values = laq_set_share_values,
459         .get_share_values = laq_get_share_values,
460         .get_stats = laq_get_stats,
461         .change_resclass = laq_change_resclass,
462         //.res_initcls       = laq_res_initcls,  //HUBERTUS: unnecessary !!
463 };
464
465 int __init init_ckrm_laq_res(void)
466 {
467         struct ckrm_classtype *clstype;
468         int resid;
469
470         clstype = ckrm_find_classtype_by_name("socket_class");
471         if (clstype == NULL) {
472                 printk(KERN_INFO " Unknown ckrm classtype<socket_class>");
473                 return -ENOENT;
474         }
475
476         if (my_resid == -1) {
477                 resid = ckrm_register_res_ctlr(clstype, &laq_rcbs);
478                 if (resid >= 0)
479                         my_resid = resid;
480                 printk("........init_ckrm_listen_aq_res -> %d\n", my_resid);
481         }
482         return 0;
483
484 }
485
486 void __exit exit_ckrm_laq_res(void)
487 {
488         ckrm_unregister_res_ctlr(&laq_rcbs);
489         my_resid = -1;
490 }
491
492 module_init(init_ckrm_laq_res)
493     module_exit(exit_ckrm_laq_res)
494
495     MODULE_LICENSE("GPL");