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)
37 #define CKRM_SAQ_MAX_DEPTH 3 // 0 => /rcfs
39 // 2 => socket_aq/listen_class
40 // 3 => socket_aq/listen_class/accept_queues
43 typedef struct ckrm_laq_res {
46 struct ckrm_shares shares;
47 struct ckrm_core_class *core;
48 struct ckrm_core_class *pcore;
51 unsigned int min_ratio;
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 *);
60 void laq_res_hold(struct ckrm_laq_res *res)
62 atomic_inc(&res->refcnt);
66 void laq_res_put(struct ckrm_laq_res *res)
68 if (atomic_dec_and_test(&res->refcnt))
73 /* Initialize rescls values
75 static void laq_res_initcls(void *my_res)
77 ckrm_laq_res_t *res = my_res;
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;
87 static int atoi(char *s)
91 k = *s++ - '0' + (k * 10);
95 static char *laq_get_name(struct ckrm_core_class *c)
97 char *p = (char *)c->name;
101 while (*p != '/' && p != c->name)
107 static void *laq_res_alloc(struct ckrm_core_class *core,
108 struct ckrm_core_class *parent)
110 ckrm_laq_res_t *res, *pres;
114 pres = ckrm_get_res_class(parent, my_resid, ckrm_laq_res_t);
118 if (core == core->classtype->default_class)
123 pdepth = 1 + pres->my_depth;
126 res = kmalloc(sizeof(ckrm_laq_res_t), GFP_ATOMIC);
128 memset(res, 0, sizeof(res));
129 spin_lock_init(&res->reslock);
131 res->my_depth = pdepth;
132 if (pdepth == 2) // listen class
134 else if (pdepth == 3)
135 res->my_id = atoi(laq_get_name(core));
139 // rescls in place, now initialize contents other than
140 // hierarchy pointers
141 laq_res_initcls(res); // acts as initialising value
147 static void laq_res_free(void *my_res)
149 ckrm_laq_res_t *res = (ckrm_laq_res_t *) my_res;
150 ckrm_laq_res_t *parent;
155 if (res->my_depth != 3) {
160 parent = ckrm_get_res_class(res->pcore, my_resid, ckrm_laq_res_t);
161 if (!parent) // Should never happen
164 spin_lock(&parent->reslock);
165 spin_lock(&res->reslock);
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);
171 spin_unlock(&res->reslock);
173 spin_unlock(&parent->reslock);
177 /**************************************************************************
179 **************************************************************************/
181 void laq_set_aq_value(struct ckrm_net_struct *ns, unsigned int *aq_ratio)
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];
191 void laq_set_aq_values(ckrm_laq_res_t * parent, unsigned int *aq_ratio)
194 struct ckrm_net_struct *ns;
195 struct ckrm_core_class *core = parent->core;
198 list_for_each_entry(ns, &core->objlist, ckrm_link) {
199 laq_set_aq_value(ns, aq_ratio);
205 static void calculate_aq_ratios(ckrm_laq_res_t * res, unsigned int *aq_ratio)
207 struct ckrm_hnode *chnode;
208 ckrm_laq_res_t *child;
212 min = aq_ratio[0] = (unsigned int)res->shares.unused_guarantee;
214 list_for_each_entry(chnode, &res->core->hnode.children, siblings) {
215 child = hnode_2_core(chnode)->res_class[my_resid];
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;
228 // default takes all if nothing specified
231 res->min_ratio = min;
233 for (i = 0; i < NUM_ACCEPT_QUEUES; i++)
234 aq_ratio[i] = aq_ratio[i] / min;
237 static int laq_set_share_values(void *my_res, struct ckrm_shares *shares)
239 ckrm_laq_res_t *res = my_res;
240 ckrm_laq_res_t *parent;
241 unsigned int aq_ratio[NUM_ACCEPT_QUEUES];
248 // something is badly wrong
249 printk(KERN_ERR "socketaq internal inconsistency\n");
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
257 // Ensure that we ignore limit values
258 shares->my_limit = CKRM_SHARE_DONTCARE;
259 shares->max_limit = CKRM_SHARE_UNCHANGED;
261 if (res->my_depth == 0) {
262 printk(KERN_ERR "socketaq bad entry\n");
264 } else if (res->my_depth == 1) {
265 // can't be written to. This is an internal default.
267 } else if (res->my_depth == 2) {
269 if (!shares->total_guarantee) {
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;
279 ckrm_lock_hier(parent->pcore);
280 spin_lock(&parent->reslock);
281 rc = set_shares(shares, &res->shares,
282 (parent == res) ? NULL : &parent->shares);
284 spin_unlock(&res->reslock);
285 ckrm_unlock_hier(res->pcore);
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);
296 static int laq_get_share_values(void *my_res, struct ckrm_shares *shares)
298 ckrm_laq_res_t *res = my_res;
302 *shares = res->shares;
306 /**************************************************************************
308 **************************************************************************/
311 laq_print_aq_stats(struct seq_file *sfile, struct tcp_acceptq_info *taq, int i)
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));
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;
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));
336 laq_get_aq_stats(ckrm_laq_res_t * pres, ckrm_laq_res_t * mres,
337 struct tcp_acceptq_info *taq)
339 struct ckrm_net_struct *ns;
340 struct ckrm_core_class *core = pres->core;
346 z = NUM_ACCEPT_QUEUES;
350 // XXX Instead of holding a class_lock introduce a rw
351 // lock to be write locked by listen callbacks and read locked here.
353 class_lock(pres->core);
354 list_for_each_entry(ns, &core->objlist, ckrm_link) {
355 tp = tcp_sk(ns->ns_sk);
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;
363 class_unlock(pres->core);
366 static int laq_get_stats(void *my_res, struct seq_file *sfile)
368 ckrm_laq_res_t *res = my_res;
369 ckrm_laq_res_t *parent;
370 struct tcp_acceptq_info taq[NUM_ACCEPT_QUEUES];
377 // something is badly wrong
378 printk(KERN_ERR "socketaq internal inconsistency\n");
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");
388 memset(taq, 0, sizeof(struct tcp_acceptq_info) * NUM_ACCEPT_QUEUES);
390 switch (res->my_depth) {
394 printk(KERN_ERR "socket class bad entry\n");
398 case 1: // can't be read from. this is internal default.
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
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
422 * The network connection is reclassified to this class. Update its shares.
423 * The socket lock is held.
425 static void laq_change_resclass(void *n, void *old, void *r)
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];
431 if (res->my_depth != 2)
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);
453 struct ckrm_res_ctlr laq_rcbs = {
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 !!
465 int __init init_ckrm_laq_res(void)
467 struct ckrm_classtype *clstype;
470 clstype = ckrm_find_classtype_by_name("socket_class");
471 if (clstype == NULL) {
472 printk(KERN_INFO " Unknown ckrm classtype<socket_class>");
476 if (my_resid == -1) {
477 resid = ckrm_register_res_ctlr(clstype, &laq_rcbs);
480 printk("........init_ckrm_listen_aq_res -> %d\n", my_resid);
486 void __exit exit_ckrm_laq_res(void)
488 ckrm_unregister_res_ctlr(&laq_rcbs);
492 module_init(init_ckrm_laq_res)
493 module_exit(exit_ckrm_laq_res)
495 MODULE_LICENSE("GPL");