00001 #include "qres_config.h"
00002 #define QOS_DEBUG_LEVEL QSUP_MOD_DEBUG_LEVEL
00003 #include <linux/aquosa/qos_debug.h>
00004
00005 #ifdef PROF_QSUP_MOD
00006 # define QOS_PROFILE
00007 #endif
00008 #include <linux/aquosa/qos_prof.h>
00009
00010 #include "qsup.h"
00011
00012 #include <linux/aquosa/qos_memory.h>
00013 #include <linux/aquosa/qos_ul.h>
00014
00032 qsup_group_rule_t *group_rules = 0;
00033 int num_group_rules = 0;
00034
00035 qsup_user_rule_t *user_rules = 0;
00036 int num_user_rules = 0;
00037
00038 qos_bw_t spare_bw = 0;
00039
00041 typedef long int qsup_coeff_t;
00042
00044 #define QSUP_COEFF_BITS 16
00045
00047 #define QSUP_COEFF_ONE (1ul << QSUP_COEFF_BITS)
00048
00050
00051 #define coeff_apply(a, b) ((unsigned long) ul_mul_shr((__u32) (a), (__u32) (b), QSUP_COEFF_BITS) )
00052
00054
00055 #define coeff_compute(a, b) ((unsigned long) ul_shl_div((__u32) (a), QSUP_COEFF_BITS, (__u32) (b)) )
00056
00057 #define MAX_NUM_LEVELS 2
00058
00059 static qsup_constraints_t default_constraint = {
00060 .level = 0,
00061 .weight = 1,
00062 .max_bw = U_LUB,
00063 .max_min_bw = U_LUB,
00064 .flags_mask = 0x00000000
00065 };
00066
00068 qsup_server_t *qsup_servers;
00069
00071 int next_server_id;
00072
00074 typedef struct qsup_user_t {
00075 int uid;
00076 qos_bw_t user_req;
00077 qsup_coeff_t user_coeff;
00078 qos_bw_t user_gua;
00079 qos_bw_t user_used_gua;
00080 struct qsup_user_t *next;
00081 } qsup_user_t;
00082
00084 typedef struct qsup_level_t {
00085 qos_bw_t level_max;
00086 qos_bw_t level_req;
00087 qos_bw_t level_sum;
00088 qsup_coeff_t level_coeff;
00089 qos_bw_t level_gua;
00090 } qsup_level_t;
00091
00093 static qsup_user_t *qsup_users;
00095 static qsup_level_t qsup_levels[MAX_NUM_LEVELS];
00096
00098 static qos_bw_t tot_gua_bw = 0;
00100 static qos_bw_t tot_used_gua_bw = 0;
00101
00104
00105
00107 static inline void qsup_lock_coeffs_read(unsigned long *p_flags) {
00108
00110 }
00111
00113 static inline void qsup_unlock_coeffs_read(unsigned long flags) {
00114
00115 }
00116
00118 static inline void qsup_lock_coeffs_write(unsigned long *p_flags) {
00119
00120 }
00121
00123 static inline void qsup_unlock_coeffs_write(unsigned long flags) {
00124
00125 }
00126
00127 static inline qos_bw_t bw_min(qos_bw_t a, qos_bw_t b) { return ((a < b) ? (a) : (b)); }
00128
00129 qos_rv qsup_add_level_rule(int level, qos_bw_t max_bw) {
00130 if (level < 0 || level >= MAX_NUM_LEVELS)
00131 return QOS_E_INVALID_PARAM;
00132
00133
00134 qsup_levels[level].level_max = bw_min(max_bw, U_LUB);
00135
00136 return QOS_OK;
00137 }
00138
00139 qos_rv qsup_add_group_constraints(int gid, qsup_constraints_t *constr) {
00140 qsup_group_rule_t *rule = qos_create(qsup_group_rule_t);
00141 if (rule == 0)
00142 return QOS_E_NO_MEMORY;
00143 rule->gid = gid;
00144 rule->constr = *constr;
00145
00146 rule->next = group_rules;
00147 group_rules = rule;
00148
00149 num_group_rules++;
00150 return QOS_OK;
00151 }
00152
00153 qos_rv qsup_add_user_constraints(int uid, qsup_constraints_t *constr) {
00154 qsup_user_rule_t *rule = qos_malloc(sizeof(qsup_user_rule_t));
00155 if (rule == 0)
00156 return QOS_E_NO_MEMORY;
00157 rule->uid = uid;
00158 rule->constr = *constr;
00159
00160 rule->next = user_rules;
00161 user_rules = rule;
00162
00163 num_user_rules++;
00164 return QOS_OK;
00165 }
00166
00167 qos_rv qsup_init() {
00168 int l;
00169 group_rules = 0;
00170 num_group_rules = 0;
00171 user_rules = 0;
00172 num_user_rules = 0;
00173 qsup_servers = 0;
00174 next_server_id = 0;
00175
00176 for (l=0; l<MAX_NUM_LEVELS; l++) {
00177 qsup_levels[l].level_coeff = QSUP_COEFF_ONE;
00178 qsup_levels[l].level_max = U_LUB;
00179 }
00180 tot_gua_bw = 0;
00181 tot_used_gua_bw = 0;
00182
00183 return QOS_OK;
00184 }
00185
00186 qos_rv qsup_cleanup() {
00187 qsup_server_t *srv = qsup_servers;
00188 qsup_user_t *usr = qsup_users;
00189
00190
00191 while (srv != 0) {
00192 qsup_server_t *tmp = srv;
00193 srv = srv->next;
00194 qos_free(tmp);
00195 }
00196
00197 while (usr != 0) {
00198 qsup_user_t *tmp = usr;
00199 usr = usr->next;
00200 qos_free(tmp);
00201 }
00202
00203 while (group_rules != 0) {
00204 qsup_group_rule_t *tmp = group_rules;
00205 group_rules = group_rules->next;
00206 qos_free(tmp);
00207 }
00208
00209 while (user_rules != 0) {
00210 qsup_user_rule_t *tmp = user_rules;
00211 user_rules = user_rules->next;
00212 qos_free(tmp);
00213 }
00214 return QOS_OK;
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 qsup_constraints_t *qsup_find_constr(int uid, int gid) {
00227 qsup_user_rule_t *urule = user_rules;
00228 qsup_group_rule_t *grule;
00229
00230 while (urule != 0)
00231 if (urule->uid == uid)
00232 return &urule->constr;
00233 else
00234 urule = urule->next;
00235
00236 grule = group_rules;
00237 while (grule != 0)
00238 if (grule->gid == gid)
00239 return &grule->constr;
00240 else
00241 grule = grule->next;
00242
00243 return &default_constraint;
00244 }
00245
00248 qsup_server_t *qsup_find_server_by_id(int server_id) {
00249 qsup_server_t *srv = qsup_servers;
00250 while ((srv != 0) && (srv->server_id != server_id))
00251 srv = srv->next;
00252 return srv;
00253 }
00254
00259 qos_rv get_user_info(qsup_user_t **pp, int uid) {
00260 qsup_user_t *usr = qsup_users;
00261 while ((usr != 0) && (usr->uid != uid))
00262 usr = usr->next;
00263 if (usr == 0) {
00265 usr = qos_malloc(sizeof(qsup_user_t));
00266 if (usr == 0)
00267 return QOS_E_NO_MEMORY;
00269 usr->next = qsup_users;
00270 qsup_users = usr;
00272 usr->uid = uid;
00273 usr->user_req = 0;
00274 usr->user_gua = 0;
00275 usr->user_used_gua = 0;
00276 usr->user_coeff = QSUP_COEFF_ONE;
00277 }
00278 *pp = usr;
00279 return QOS_OK;
00280 }
00281
00282 qos_bw_t qsup_get_max_gua_bw(int uid, int gid) {
00283 qsup_constraints_t *constr;
00284 constr = qsup_find_constr(uid, gid);
00285 return constr->max_min_bw;
00286 }
00287
00288 qos_rv qsup_get_avail_gua_bw(int uid, int gid, qos_bw_t *p_avail_bw) {
00289 qos_rv rv = QOS_OK;
00290 qsup_constraints_t *constr;
00291 qsup_user_t *usr;
00292
00293 constr = qsup_find_constr(uid, gid);
00294 rv = get_user_info(&usr, uid);
00295 qos_chk_go_msg(rv == QOS_OK, end, "get_user_info() failed");
00296 *p_avail_bw = constr->max_min_bw - usr->user_gua;
00297
00298 end:
00299
00300 return rv;
00301 }
00302
00303 qos_rv qsup_get_avail_bw(int uid, int gid, qos_bw_t *p_avail_bw) {
00304 qos_rv rv = QOS_OK;
00305 qsup_constraints_t *constr;
00306 qsup_user_t *usr;
00307
00308 constr = qsup_find_constr(uid, gid);
00309 rv = get_user_info(&usr, uid);
00310 qos_chk_go_msg(rv == QOS_OK, end, "get_user_info() failed");
00311 *p_avail_bw = constr->max_bw - usr->user_req;
00312
00313 end:
00314
00315 return rv;
00316 }
00317
00319 qos_rv qsup_init_server(qsup_server_t *srv, int uid, int gid, qres_params_t *param) {
00320 qsup_user_t *usr;
00321 qsup_constraints_t *constr;
00322 qos_bw_t new_tot_gua;
00323 qos_bw_t min_bw;
00324
00325 min_bw = r2bw_ceil(param->Q_min, param->P);
00326
00328 qos_log_debug("Adding server: uid=%d gid=%d min_bw=%ld", uid, gid, min_bw);
00329 constr = qsup_find_constr(uid, gid);
00330
00331 if (param->flags & constr->flags_mask) {
00332 qos_log_err("Required flags violates configured mask for user/group");
00333 return QOS_E_UNAUTHORIZED;
00334 }
00335
00336 if (min_bw > constr->max_min_bw) {
00337 qos_log_err("Minimum guaranteed requested violates max_min");
00338
00339 return QOS_E_UNAUTHORIZED;
00340 }
00341
00342
00343 new_tot_gua = tot_gua_bw + min_bw;
00344 if (new_tot_gua > U_LUB - spare_bw) {
00345 qos_log_err("New guaranteed task rejected");
00346 return QOS_E_SYSTEM_OVERLOAD;
00347 }
00348
00349 qos_chk_ok_ret(get_user_info(&usr, uid));
00350
00351 if (usr->user_gua + min_bw > U_LUB - spare_bw) {
00352 qos_log_err("Minimum guaranteed requested by all user apps violates U_LUB - spare_bw");
00353 return QOS_E_SYSTEM_OVERLOAD;
00354 }
00355
00356 if (usr->user_gua + min_bw > constr->max_min_bw) {
00357 qos_log_err("Minimum guaranteed requested by all user apps violates max_min");
00358 return QOS_E_UNAUTHORIZED;
00359 }
00360
00361 srv->server_id = next_server_id++;
00362 srv->level = constr->level;
00363 srv->weight = constr->weight;
00364 srv->max_user_bw = constr->max_bw;
00365 srv->max_level_bw = qsup_levels[srv->level].level_max;
00366 srv->uid = uid;
00367 srv->gid = gid;
00368 srv->req_bw = 0;
00369 srv->gua_bw = min_bw;
00370 srv->used_gua_bw = 0;
00371 srv->p_level_sum = &qsup_levels[srv->level].level_sum;
00372 srv->p_level_req = &qsup_levels[srv->level].level_req;
00373 srv->p_level_coeff = &qsup_levels[srv->level].level_coeff;
00374 srv->p_level_gua = &qsup_levels[srv->level].level_gua;
00375 srv->p_user_req = &usr->user_req;
00376 srv->p_user_coeff = &usr->user_coeff;
00377 srv->p_user_gua = &usr->user_used_gua;
00378
00379
00380 srv->next = qsup_servers;
00381 qsup_servers = srv;
00382
00384 tot_gua_bw = new_tot_gua;
00385
00386 return QOS_OK;
00387 }
00388
00389 qos_rv qsup_create_server(qsup_server_t **pp, int uid, int gid, qres_params_t *param) {
00390 qsup_server_t *qsup;
00391 qos_rv rv;
00392 qsup = qos_create(qsup_server_t);
00393 if (qsup == 0)
00394 return QOS_E_NO_MEMORY;
00395 rv = qsup_init_server(qsup, uid, gid, param);
00396 if (rv != QOS_OK) {
00397 qos_log_err("qsup_init_server() failed: %s", qos_strerror(rv));
00398 qos_free(qsup);
00399 return rv;
00400 }
00401 *pp = qsup;
00402 return QOS_OK;
00403 }
00404
00405 qos_rv qsup_cleanup_server(qsup_server_t *srv) {
00406 qsup_server_t *tmp = qsup_servers;
00407 prof_vars;
00408
00409 prof_func();
00410
00411 if (tmp == 0)
00412 prof_return(QOS_E_INCONSISTENT_STATE);
00413
00414
00415 if (srv->req_bw != 0) {
00416 qos_rv err = qsup_set_required_bw(srv, 0);
00417 if (err != QOS_OK)
00418 prof_return(err);
00419 }
00420
00421
00422 tot_gua_bw -= srv->gua_bw;
00423
00424
00425 if (srv == qsup_servers)
00426 qsup_servers = srv->next;
00427 else {
00428 while ((tmp->next != 0) && (tmp->next != srv))
00429 tmp = tmp->next;
00430 if (tmp->next == 0)
00431 prof_return(QOS_E_INVALID_PARAM);
00432 tmp->next = srv->next;
00433 }
00434
00435 prof_end();
00436
00437 return QOS_OK;
00438 }
00439
00440 qos_rv qsup_destroy_server(qsup_server_t *srv) {
00441 qos_rv rv = qsup_cleanup_server(srv);
00442
00443 qos_free(srv);
00444 return rv;
00445 }
00446
00447 qos_rv qsup_set_required_bw(qsup_server_t *srv, qos_bw_t server_req) {
00448 qos_bw_t user_req;
00449 qos_bw_t level_req;
00450 int l;
00451 qos_bw_t avail_bw;
00452 qos_bw_t used_gua_bw;
00453 prof_vars;
00454
00455 qos_log_debug("Changing required bw of server %d from " QOS_BW_FMT " to " QOS_BW_FMT,
00456 srv->server_id, srv->req_bw, server_req);
00457
00458 prof_func();
00459
00460
00461
00462 if (server_req > srv->max_user_bw) {
00463 qos_log_debug("Saturating request from " QOS_BW_FMT " to " QOS_BW_FMT,
00464 server_req, srv->max_user_bw);
00465 server_req = srv->max_user_bw;
00466 }
00467
00468
00469 used_gua_bw = bw_min(server_req, srv->gua_bw);
00470
00471 *(srv->p_user_gua) += used_gua_bw - srv->used_gua_bw;
00472 *(srv->p_level_gua) += used_gua_bw - srv->used_gua_bw;
00473 tot_used_gua_bw += used_gua_bw - srv->used_gua_bw;
00474
00475 srv->used_gua_bw = used_gua_bw;
00476
00477
00478 user_req = *(srv->p_user_req) - srv->req_bw + server_req;
00479
00480 qos_log_debug("Updated sum of user-reqs: " QOS_BW_FMT, user_req);
00481
00482
00483
00484 if (user_req > srv->max_user_bw) {
00485 qos_log_debug("Rescaling per-user request of " QOS_BW_FMT " to max=" QOS_BW_FMT,
00486 user_req, srv->max_user_bw);
00487 *(srv->p_user_coeff) = coeff_compute(srv->max_user_bw - *(srv->p_user_gua), user_req - *(srv->p_user_gua));
00488 } else {
00489 #ifndef QSUP_EXPAND
00490 *(srv->p_user_coeff) = QSUP_COEFF_ONE;
00491 #else
00492
00493 if (user_req - *(srv->p_user_gua) == 0)
00494 *(srv->p_user_coeff) = QSUP_COEFF_ONE;
00495 else
00496 *(srv->p_user_coeff) = coeff_compute(srv->max_user_bw - *(srv->p_user_gua), user_req - *(srv->p_user_gua));
00497 #endif
00498 }
00499
00500
00501 level_req = (*(srv->p_level_req)) - bw_min(*(srv->p_user_req), srv->max_user_bw) + bw_min(user_req, srv->max_user_bw);
00502
00503
00504 srv->req_bw = server_req;
00505 *(srv->p_user_req) = user_req;
00506 *(srv->p_level_req) = level_req;
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516 avail_bw = U_LUB;
00517 for (l=0; l<MAX_NUM_LEVELS; l++) {
00518 qsup_level_t *lev = &qsup_levels[l];
00519
00520
00521 qos_bw_t assigned;
00522
00523
00524 assigned = bw_min(bw_min(lev->level_req, lev->level_max), avail_bw);
00525
00526
00527
00528 lev->level_sum = assigned;
00529
00530
00531
00532 if (lev->level_req > lev->level_gua) {
00533
00534 lev->level_coeff = coeff_compute(assigned - lev->level_gua, lev->level_req - lev->level_gua);
00535 } else
00536 lev->level_coeff = QSUP_COEFF_ONE;
00537
00538 avail_bw -= assigned;
00539 }
00540
00541 prof_end();
00542
00543 return QOS_OK;
00544 }
00545
00546 qos_bw_t qsup_get_required_bw(qsup_server_t *srv) {
00547 return srv->req_bw;
00548 }
00549
00550 qos_bw_t qsup_get_guaranteed_bw(qsup_server_t *srv) {
00551 return srv->gua_bw;
00552 }
00553
00554 void qsup_dump(void) {
00555 int l;
00556 qsup_user_t *usr;
00557 qsup_server_t *srv;
00558
00559 qos_log_debug("Current user coefficients:");
00560 for (usr = qsup_users; usr != 0; usr = usr->next)
00561 qos_log_debug("User %d: coeff=%lu/1000", usr->uid, coeff_apply(usr->user_coeff, 1000));
00562
00563 qos_log_debug("Current level coefficients:");
00564 for (l = 0; l < MAX_NUM_LEVELS; l++)
00565 qos_log_debug("Level %d: coeff=%lu/1000", l, coeff_apply(qsup_levels[l].level_coeff, 1000));
00566
00567 qos_log_debug("Current list of servers:");
00568 for (srv = qsup_servers; srv != 0; srv = srv->next) {
00569 qos_log_debug("Server %d: lev=%d req=" QRES_TIME_FMT "/1000 eff=" QRES_TIME_FMT "/1000",
00570 srv->server_id, srv->level,
00571 bw2Q(srv->req_bw, 1000),
00572
00573 bw2Q(qsup_get_approved_bw(srv), 1000));
00574 }
00575 }
00576
00577 qos_bw_t qsup_get_approved_bw(qsup_server_t *srv) {
00578 qos_bw_t bw;
00579 qsup_coeff_t c1, c2;
00580 prof_vars;
00581
00582 prof_func();
00583 bw = srv->used_gua_bw;
00584 c1 = *(srv->p_level_coeff);
00585 c2 = *(srv->p_user_coeff);
00586
00587 bw += coeff_apply(coeff_apply(srv->req_bw - srv->used_gua_bw, c2), c1);
00588 prof_return(bw);
00589 }
00590
00594 qos_rv qsup_reserve_spare(qos_bw_t bw) {
00595 if (bw > U_LUB)
00596 return QOS_E_INVALID_PARAM;
00597 if (qsup_servers != NULL)
00598 return QOS_E_INCONSISTENT_STATE;
00599 spare_bw = bw;
00600
00601 return QOS_OK;
00602 }
00603