1 /* ckrm_socketaq.c - accept queue resource controller
3 * Copyright (C) Vivek Kashyap, IBM Corp. 2004
5 * Latest version, more details at http://ckrm.sf.net
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.
18 /* Code Description: TBD
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>
32 #include <linux/ckrm_net.h>
34 #define hnode_2_core(ptr) \
35 ((ptr) ? container_of(ptr, struct ckrm_core_class, hnode) : NULL)
38 #define CKRM_SAQ_MAX_DEPTH 3 // 0 => /rcfs
40 // 2 => socket_aq/listen_class
41 // 3 => socket_aq/listen_class/accept_queues
44 typedef struct ckrm_laq_res {
47 struct ckrm_shares shares;
48 struct ckrm_core_class *core;
49 struct ckrm_core_class *pcore;
54 static int my_resid = -1;
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 * ) ;
61 laq_res_hold(struct ckrm_laq_res *res)
63 atomic_inc(&res->refcnt);
68 laq_res_put(struct ckrm_laq_res *res)
70 if (atomic_dec_and_test(&res->refcnt))
75 /* Initialize rescls values
78 laq_res_initcls(void *my_res)
80 ckrm_laq_res_t *res = my_res;
82 res->shares.my_guarantee = CKRM_SHARE_DONTCARE;
83 res->shares.my_limit = CKRM_SHARE_DONTCARE;
84 res->shares.total_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
85 res->shares.max_limit = CKRM_SHARE_DFLT_MAX_LIMIT;
86 res->shares.unused_guarantee = CKRM_SHARE_DFLT_TOTAL_GUARANTEE;
87 res->shares.cur_max_limit = 0;
95 k = *s++ - '0' + (k * 10);
100 laq_get_name(struct ckrm_core_class *c)
102 char *p = (char *)c->name;
106 while( *p != '/' && p != c->name)
113 laq_res_alloc(struct ckrm_core_class *core, struct ckrm_core_class *parent)
115 ckrm_laq_res_t *res, *pres;
119 pres = ckrm_get_res_class(parent, my_resid, ckrm_laq_res_t);
123 if (core == core->classtype->default_class)
128 pdepth = 1 + pres->my_depth;
131 res = kmalloc(sizeof(ckrm_laq_res_t), GFP_ATOMIC);
133 memset(res, 0, sizeof(res));
134 spin_lock_init(&res->reslock);
136 res->my_depth = pdepth;
137 if (pdepth == 2) // listen class
139 else if (pdepth == 3)
140 res->my_id = atoi(laq_get_name(core));
144 // rescls in place, now initialize contents other than
145 // hierarchy pointers
146 laq_res_initcls(res); // acts as initialising value
153 laq_res_free(void *my_res)
155 ckrm_laq_res_t *res = (ckrm_laq_res_t *)my_res;
156 ckrm_laq_res_t *parent;
161 if (res->my_depth != 3) {
166 parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t);
167 if (!parent) // Should never happen
170 spin_lock(&parent->reslock);
171 spin_lock(&res->reslock);
173 // return child's guarantee to parent node
174 // Limits have no meaning for accept queue control
175 child_guarantee_changed(&parent->shares, res->shares.my_guarantee, 0);
177 spin_unlock(&res->reslock);
179 spin_unlock(&parent->reslock);
183 /**************************************************************************
185 **************************************************************************/
188 laq_set_aq_values(ckrm_laq_res_t *my_res, ckrm_laq_res_t *parent, int updatep)
191 struct ckrm_net_struct *ns;
192 struct ckrm_core_class *core = parent->core;
195 if (my_res->my_depth < 2)
198 // XXX Instead of holding a class_lock introduce a rw
199 // lock to be write locked by listen callbacks and read locked here.
202 list_for_each_entry(ns, &core->objlist,ckrm_link) {
203 tp = tcp_sk(ns->ns_sk);
205 tp->acceptq[0].aq_ratio =
206 parent->shares.total_guarantee/
207 parent->shares.unused_guarantee;
209 tp->acceptq[my_res->my_id].aq_ratio =
210 my_res->shares.total_guarantee/
211 parent->shares.my_guarantee;
218 laq_set_share_values(void *my_res, struct ckrm_shares *shares)
220 ckrm_laq_res_t *res = my_res;
221 ckrm_laq_res_t *parent, *child;
222 struct ckrm_hnode *chnode;
229 // something is badly wrong
230 printk(KERN_ERR "socketaq internal inconsistency\n");
234 parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t);
235 if (!parent) // socket_class does not have a share interface
238 // Ensure that we ignore limit values
239 shares->my_limit = shares->max_limit = CKRM_SHARE_UNCHANGED;
241 switch (res->my_depth) {
243 case 0: printk(KERN_ERR "socketaq bad entry\n");
247 case 1: // can't be written to. this is internal default.
252 case 2: // nothing to inherit
253 if (!shares->total_guarantee) {
258 ckrm_lock_hier(res->pcore);
259 spin_lock(&res->reslock);
260 rc = set_shares(shares, &res->shares, NULL);
262 list_for_each_entry(chnode,
263 &res->core->hnode.children,siblings){
264 child=hnode_2_core(chnode)->res_class[my_resid];
265 laq_set_aq_values(child,res,(child->my_id==1));
268 spin_unlock(&res->reslock);
269 ckrm_unlock_hier(res->pcore);
272 case 3: // accept queue itself. Check against parent.
273 ckrm_lock_hier(parent->pcore);
274 spin_lock(&parent->reslock);
275 rc = set_shares(shares, &res->shares, &parent->shares);
277 laq_set_aq_values(res,parent,1);
279 spin_unlock(&parent->reslock);
280 ckrm_unlock_hier(parent->pcore);
288 laq_get_share_values(void *my_res, struct ckrm_shares *shares)
290 ckrm_laq_res_t *res = my_res;
294 *shares = res->shares;
298 /**************************************************************************
300 **************************************************************************/
303 laq_print_aq_stats(struct seq_file *sfile, struct tcp_acceptq_info *taq, int i)
305 seq_printf(sfile, "Class %d connections:\n\taccepted: %u\n\t"
306 "queued: %u\n\twait_time: %lu\n\t",
307 i, taq->acceptq_count, taq->acceptq_qcount,
308 taq->acceptq_wait_time);
313 for (i = 1; i < NUM_ACCEPT_QUEUES; i++) {
314 taq[0].acceptq_wait_time += taq[i].acceptq_wait_time;
315 taq[0].acceptq_qcount += taq[i].acceptq_qcount;
316 taq[0].acceptq_count += taq[i].acceptq_count;
319 seq_printf(sfile, "Totals :\n\taccepted: %u\n\t"
320 "queued: %u\n\twait_time: %lu\n",
321 taq->acceptq_count, taq->acceptq_qcount,
322 taq->acceptq_wait_time);
328 laq_get_aq_stats(ckrm_laq_res_t *pres, ckrm_laq_res_t *mres,
329 struct tcp_acceptq_info *taq)
331 struct ckrm_net_struct *ns;
332 struct ckrm_core_class *core = pres->core;
338 z = NUM_ACCEPT_QUEUES;
342 // XXX Instead of holding a class_lock introduce a rw
343 // lock to be write locked by listen callbacks and read locked here.
345 class_lock(pres->core);
346 list_for_each_entry(ns, &core->objlist,ckrm_link) {
347 tp = tcp_sk(ns->ns_sk);
349 taq->acceptq_wait_time += tp->acceptq[a].aq_wait_time;
350 taq->acceptq_qcount += tp->acceptq[a].aq_qcount;
351 taq->acceptq_count += tp->acceptq[a].aq_count;
355 class_unlock(pres->core);
360 laq_get_stats(void *my_res, struct seq_file *sfile)
362 ckrm_laq_res_t *res = my_res;
363 ckrm_laq_res_t *parent;
364 struct tcp_acceptq_info taq[NUM_ACCEPT_QUEUES];
371 // something is badly wrong
372 printk(KERN_ERR "socketaq internal inconsistency\n");
376 parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t);
377 if (!parent) { // socket_class does not have a stat interface
378 printk(KERN_ERR "socketaq internal fs inconsistency\n");
382 memset(taq, 0, sizeof(struct tcp_acceptq_info) * NUM_ACCEPT_QUEUES);
384 switch (res->my_depth) {
387 case 0: printk(KERN_ERR "socket class bad entry\n");
391 case 1: // can't be read from. this is internal default.
396 case 2: // return the default and total
397 ckrm_lock_hier(res->core); // block any deletes
398 laq_get_aq_stats(res, res, &taq[0]);
399 laq_print_aq_stats(sfile, &taq[0], 0);
400 ckrm_unlock_hier(res->core); // block any deletes
404 ckrm_lock_hier(parent->core); // block any deletes
405 laq_get_aq_stats(parent, res, &taq[res->my_id]);
406 laq_print_aq_stats(sfile, &taq[res->my_id], res->my_id);
407 ckrm_unlock_hier(parent->core); // block any deletes
415 * The network connection is reclassified to this class. Update its shares.
416 * The socket lock is held.
419 laq_change_resclass(void *n, void *old, void *r)
421 struct ckrm_net_struct *ns = (struct ckrm_net_struct *)n;
422 struct ckrm_laq_res *res = (struct ckrm_laq_res *)r;
423 struct ckrm_hnode *chnode = NULL;
426 if (res->my_depth != 2)
429 // a change to my_depth == 3 ie. the accept classes cannot happen.
430 // there is no target file
431 if (res->my_depth == 2) { // it is one of the socket classes
432 struct ckrm_laq_res *reschild;
433 struct sock *sk = ns->ns_sk;
434 struct tcp_opt *tp = tcp_sk(sk);
436 // share rule: hold parent resource lock. then self.
437 // However, since my_depth == 1 is a generic class it is not
438 // needed here. Self lock is enough.
439 spin_lock(&res->reslock);
440 tp->acceptq[0].aq_ratio = res->shares.total_guarantee/
441 res->shares.unused_guarantee;
442 list_for_each_entry(chnode,&res->core->hnode.children,siblings){
443 reschild = hnode_2_core(chnode)->res_class[my_resid];
445 spin_lock(&reschild->reslock);
446 tp->acceptq[reschild->my_id].aq_ratio=
447 reschild->shares.total_guarantee/
448 res->shares.my_guarantee;
449 spin_unlock(&reschild->reslock);
451 spin_unlock(&res->reslock);
457 struct ckrm_res_ctlr laq_rcbs = {
459 .resid = -1 , // dynamically assigned
460 .res_alloc = laq_res_alloc,
461 .res_free = laq_res_free,
462 .set_share_values = laq_set_share_values,
463 .get_share_values = laq_get_share_values,
464 .get_stats = laq_get_stats,
465 .change_resclass = laq_change_resclass,
466 // .res_initcls = laq_res_initcls, // LAQ_HUBERTUS: no need for this !!
470 init_ckrm_laq_res(void)
472 struct ckrm_classtype *clstype;
475 clstype = ckrm_find_classtype_by_name("socket_class");
476 if (clstype == NULL) {
477 printk(KERN_INFO " Unknown ckrm classtype<socket_class>");
481 if (my_resid == -1) {
482 resid = ckrm_register_res_ctlr(clstype,&laq_rcbs);
485 printk("........init_ckrm_listen_aq_res -> %d\n",my_resid);
492 exit_ckrm_laq_res(void)
494 ckrm_unregister_res_ctlr(&laq_rcbs);
499 module_init(init_ckrm_laq_res)
500 module_exit(exit_ckrm_laq_res)
502 MODULE_LICENSE("GPL");