|
|
1.1 ! root 1: /* ! 2: * limits routines ! 3: */ ! 4: ! 5: #include "sys/param.h" ! 6: #include "sys/systm.h" ! 7: #include "sys/user.h" ! 8: #include "sys/file.h" ! 9: #include "sys/inode.h" ! 10: #include "sys/lnode.h" ! 11: #include "sys/proc.h" ! 12: #include "sys/share.h" ! 13: ! 14: #ifndef ETOOMANYU ! 15: #define ETOOMANYU ENOSPC /* Must go in errno.h or lnode.h */ ! 16: #endif ! 17: ! 18: float NiceDecays[2*NZERO]; /* Table for pre-calculated priority decays */ ! 19: float NiceRates[2*NZERO]; /* Table for pre-calculated rate increments */ ! 20: long NiceTicks[2*NZERO]; /* Array of costs for a cpu tick biased by p_nice */ ! 21: KL_p lastlnode; ! 22: ! 23: /* ! 24: * limits system call ! 25: * ! 26: * Functions ! 27: * ! 28: * 0 - L_MYLIM ! 29: * 9 - L_MYKN ! 30: * return own limit struct ! 31: * return number of processes attached to node ! 32: * ! 33: * 1 - L_OTHLIM ! 34: * 10- L_OTHKN ! 35: * return limit struct of l_uid ! 36: * return number of processes attached to node or ESRCH ! 37: * ! 38: * 2 - L_ALLLIM ! 39: * 11- L_ALLKN ! 40: * return all active limit structs ! 41: * return number of structs returned ! 42: * ! 43: * 3 - L_SETLIM super-user only ! 44: * initialize limit struct for l_uid ! 45: * ETOOMANYU - no spare limit structs ! 46: * ESRCH - group not installed ! 47: * ! 48: * 4 - L_DEADLIM ! 49: * wait for a dead child, return limit struct and proc entry, ! 50: * and if LASTREF, remove dead limit struct from the active list. ! 51: * LASTREF set for dead limit struct ! 52: * ECHILD - no children to wait for ! 53: * return number of processes attached to node ! 54: * ! 55: * 5 - L_CHNGLIM super-user only ! 56: * change limits for active limit struct ! 57: * ESRCH - l_uid not found ! 58: * ! 59: * 6 - L_DEADGROUP ! 60: * return limit struct for a dead group and remove group ! 61: * ESRCH - no dead groups ! 62: * ! 63: * 7 - L_GETCOSTS ! 64: * return share constants ! 65: * ! 66: * 8 - L_SETCOSTS super-user only ! 67: * set share constants ! 68: */ ! 69: limits() ! 70: { ! 71: register struct a { ! 72: struct lnode *lp; ! 73: int select; ! 74: } *uap; ! 75: register KL_p ol; ! 76: register KL_p nl; ! 77: register KL_p gl; ! 78: register int i; ! 79: register struct proc *up; ! 80: register int size; ! 81: static struct kern_lnode kl; ! 82: ! 83: up = u.u_procp; ! 84: size = sizeof(struct kern_lnode); ! 85: ! 86: uap = (struct a *)u.u_ap; ! 87: switch(uap->select) { ! 88: case L_MYLIM: ! 89: if(copyout((caddr_t)&up->p_lnode->kl, (caddr_t)uap->lp, sizeof(struct lnode))) ! 90: u.u_error = EFAULT; ! 91: u.u_r.r_val1 = up->p_lnode->kl_refcount; ! 92: return; ! 93: ! 94: case L_MYKN: ! 95: if(copyout((caddr_t)up->p_lnode, (caddr_t)uap->lp, size)) ! 96: u.u_error = EFAULT; ! 97: u.u_r.r_val1 = up->p_lnode->kl_refcount; ! 98: return; ! 99: ! 100: case L_OTHLIM: ! 101: size = sizeof(struct lnode); ! 102: case L_OTHKN: ! 103: if(copyin((caddr_t)uap->lp, (uap->select == L_OTHLIM)?(caddr_t)&kl.kl:(caddr_t)&kl, size)) { ! 104: u.u_error = EFAULT; ! 105: return; ! 106: } ! 107: for(ol = lnodes; ol != (KL_p)0; ol = ol->kl_next) { ! 108: if(ol->kl.l_uid == kl.kl.l_uid) { ! 109: if(copyout((uap->select == L_OTHLIM)?(caddr_t)&ol->kl:(caddr_t)ol, (caddr_t)uap->lp, size)) ! 110: u.u_error = EFAULT; ! 111: u.u_r.r_val1 = ol->kl_refcount; ! 112: return; ! 113: } ! 114: } ! 115: u.u_error = ESRCH; ! 116: return; ! 117: ! 118: case L_ALLLIM: ! 119: size = sizeof(struct lnode); ! 120: case L_ALLKN: ! 121: i = 0; ! 122: for(ol = lnodes; ol != (KL_p)0; ol = ol->kl_next) { ! 123: if(copyout((uap->select == L_ALLLIM)?(caddr_t)&ol->kl:(caddr_t)ol, (caddr_t)uap->lp, size)) { ! 124: u.u_error = EFAULT; ! 125: return; ! 126: } ! 127: *(caddr_t *)&uap->lp += size; ! 128: i++; ! 129: } ! 130: u.u_r.r_val1 = i; ! 131: return; ! 132: ! 133: case L_SETLIM: ! 134: if(!suser()) ! 135: return; ! 136: if(copyin((caddr_t)uap->lp, (caddr_t)&kl.kl, sizeof(struct lnode))) { ! 137: u.u_error = EFAULT; ! 138: return; ! 139: } ! 140: if(kl.kl.l_uid == up->p_lnode->kl.l_uid) ! 141: return; ! 142: nl = gl = (KL_p)0; ! 143: for(ol = lnodes, i = 0; ol < lnodesMAXUSERS; ol++) { ! 144: if(!(ol->kl.l_flags & ACTIVELNODE)) { ! 145: if(nl == NULL) ! 146: nl = ol; ! 147: continue; ! 148: } ! 149: if(ol->kl.l_uid == kl.kl.l_uid) { ! 150: nl = ol; ! 151: goto found; ! 152: } ! 153: if(!(ol->kl.l_flags & NOTSHARED) && ++i >= MAXUSERS) { ! 154: u.u_error = ETOOMANYU; ! 155: return; ! 156: } ! 157: if(ol->kl.l_uid == kl.kl.l_group) ! 158: gl = ol; /* my group */ ! 159: } ! 160: if(nl == NULL) { ! 161: u.u_error = ETOOMANYU; ! 162: return; ! 163: } ! 164: if(gl == (KL_p)0) { ! 165: u.u_error = ESRCH; /* No group installed yet */ ! 166: return; ! 167: } ! 168: if(grouplevel(gl)>=MAXGROUPS) { ! 169: u.u_error = ESRCH; /* ETOODEEPFORME? */ ! 170: return; ! 171: } ! 172: nl->kl = kl.kl; ! 173: nl->kl.l_flags &= ~CHNGDLIMITS; ! 174: nl->kl_ghead = (KL_p)0; ! 175: if(nl->kl.l_flags & NOTSHARED) ! 176: nl->kl_gshares = zerof; ! 177: else ! 178: nl->kl_gshares = nl->kl.l_shares; ! 179: nl->kl_temp = zerof; ! 180: nl->kl_children = 0; ! 181: nl->kl_cost = 0; ! 182: nl->kl_refcount = 0; ! 183: nl->kl_muse = 0; ! 184: nl->kl_rate = onef; ! 185: splshsched(); /* Hopefully, this locks out the clock scan too */ ! 186: addgroup(gl, nl); ! 187: normshares(gl, 0); ! 188: fixusage(nl); ! 189: nl->kl_prev = gl; /* insert into active list */ ! 190: if((nl->kl_next = gl->kl_next) == (KL_p)0) ! 191: lastlnode = nl; ! 192: else ! 193: gl->kl_next->kl_prev = nl; ! 194: gl->kl_next = nl; ! 195: spl0(); ! 196: found: ! 197: nl->kl.l_flags &= ~(LASTREF|DEADGROUP); ! 198: nl->kl.l_flags |= ACTIVELNODE; ! 199: ol = up->p_lnode; ! 200: if(--ol->kl_refcount == 0) { ! 201: if(ol->kl_children == 0) ! 202: ol->kl.l_flags |= DEADGROUP; ! 203: } ! 204: nl->kl_refcount++; ! 205: i = up->p_dsize + up->p_ssize; ! 206: ol->kl_muse -= i; ! 207: nl->kl_muse += i; ! 208: up->p_lnode = nl; ! 209: return; ! 210: ! 211: #if NOTDEF /* unused and unpleasant */ ! 212: case L_DEADLIM: ! 213: wait1(WRETLIM, NULL); /* will call retlimits() */ ! 214: return; ! 215: #endif ! 216: case L_DEADGROUP: ! 217: if(!suser()) ! 218: return; ! 219: for(ol = lnodes[0].kl_next; ol != (KL_p)0; ol = ol->kl_next) ! 220: if(ol->kl_refcount == 0 && ol->kl_children == 0) { ! 221: remlnode(ol); ! 222: if(copyout((caddr_t)&ol->kl, (caddr_t)uap->lp, sizeof(struct lnode))) ! 223: u.u_error = EFAULT; ! 224: return; ! 225: } ! 226: u.u_error = ESRCH; ! 227: return; ! 228: ! 229: case L_CHNGLIM: ! 230: if(!suser()) ! 231: return; ! 232: if(copyin((caddr_t)uap->lp, (caddr_t)&kl.kl, sizeof(struct lnode))) { ! 233: u.u_error = EFAULT; ! 234: return; ! 235: } ! 236: if(kl.kl.l_uid == 0) { ! 237: u.u_error = EINVAL; ! 238: return; ! 239: } ! 240: for(ol = lnodes, gl = (KL_p)0; ol != (KL_p)0; ol = ol->kl_next) { ! 241: if(ol->kl.l_uid == kl.kl.l_uid) { ! 242: if(ol->kl.l_group != kl.kl.l_group) { ! 243: if(gl==(KL_p)0) ! 244: break; /* ESRCH */ ! 245: else { ! 246: splshsched(); ! 247: remgroup(ol); ! 248: ol->kl.l_group = kl.kl.l_group; ! 249: addgroup(gl, ol); ! 250: } ! 251: } else if(gl==(KL_p)0) ! 252: panic("lost group"); ! 253: ! 254: if(ol->kl_norms && ol->kl_usage < MAXUSAGE) ! 255: TotUsage -= onef / ol->kl_usage; ! 256: ol->kl.l_usage = kl.kl.l_usage; ! 257: ! 258: if(ol->kl.l_shares != kl.kl.l_shares ! 259: || ((ol->kl.l_flags^kl.kl.l_flags) & NOTSHARED)) { ! 260: gl->kl_gshares -= ol->kl.l_shares; ! 261: if(!(ol->kl.l_flags & NOTSHARED)) ! 262: ol->kl_gshares -= ol->kl.l_shares; ! 263: ol->kl.l_shares = kl.kl.l_shares; ! 264: gl->kl_gshares += ol->kl.l_shares; ! 265: if(!(kl.kl.l_flags & NOTSHARED)) ! 266: ol->kl_gshares += ol->kl.l_shares; ! 267: } ! 268: ol->kl.l_flags &= (ACTIVELNODE|LASTREF|DEADGROUP); ! 269: ol->kl.l_flags |= (kl.kl.l_flags & ~(ACTIVELNODE|LASTREF|DEADGROUP)) | CHNGDLIMITS; ! 270: normshares(gl, 0); ! 271: fixusage(ol); ! 272: spl0(); ! 273: return; ! 274: } else if(ol->kl.l_uid == kl.kl.l_group) ! 275: gl = ol; /* Remember [new] group */ ! 276: } ! 277: u.u_error = ESRCH; ! 278: return; ! 279: ! 280: case L_GETCOSTS: ! 281: if(copyout((caddr_t)&shconsts, (caddr_t)uap->lp, sizeof shconsts)) ! 282: u.u_error = EFAULT; ! 283: return; ! 284: ! 285: case L_SETCOSTS: ! 286: if(!suser()) ! 287: return; ! 288: splshsched(); ! 289: if(copyin((caddr_t)uap->lp, (caddr_t)&shconsts, (caddr_t)&LASTPARAM - (caddr_t)&shconsts)) ! 290: u.u_error = EFAULT; ! 291: setcosts(); ! 292: spl0(); ! 293: return; ! 294: ! 295: default: ! 296: u.u_error = EINVAL; ! 297: return; ! 298: } ! 299: } ! 300: ! 301: /* ! 302: * Add to group list ! 303: */ ! 304: ! 305: addgroup(gl, kl) ! 306: register KL_p gl; ! 307: register KL_p kl; ! 308: { ! 309: kl->kl_parent = gl; ! 310: kl->kl_gnext = gl->kl_ghead; ! 311: gl->kl_ghead = kl; ! 312: gl->kl_children++; ! 313: gl->kl_gshares += kl->kl.l_shares; ! 314: gl->kl.l_flags &= ~DEADGROUP; ! 315: } ! 316: ! 317: #if NOTDEF ! 318: ! 319: /* ! 320: * Return dead proc and limits to init for accounting. ! 321: */ ! 322: ! 323: retlimits(p) ! 324: register struct proc *p; ! 325: { ! 326: register KL_p lp; ! 327: register struct a { ! 328: struct retlim *rp; ! 329: } *uap; ! 330: ! 331: lp = p->p_lnode; ! 332: if(lp->kl_refcount == 0) { ! 333: lp->kl.l_flags |= LASTREF; ! 334: if(lp->kl_children == 0) ! 335: remlnode(lp); ! 336: } ! 337: ! 338: uap = (struct a *)u.u_ap; ! 339: if(copyout((caddr_t)p, (caddr_t)&uap->rp->r_proc, sizeof(struct xproc)) ! 340: || copyout((caddr_t)&lp->kl, (caddr_t)&uap->rp->r_lnode, sizeof(struct lnode))) ! 341: u.u_error = EFAULT; ! 342: ! 343: u.u_r.r_val1 = lp->kl_refcount; ! 344: } ! 345: ! 346: #endif ! 347: ! 348: /* ! 349: * Remove lnode from active and group lists. ! 350: */ ! 351: ! 352: remlnode(lp) ! 353: register KL_p lp; ! 354: { ! 355: splshsched(); ! 356: ! 357: if((lp->kl_prev->kl_next = lp->kl_next) == (KL_p)0) ! 358: lastlnode = lp->kl_prev; ! 359: else ! 360: lp->kl_next->kl_prev = lp->kl_prev; ! 361: ! 362: remgroup(lp); ! 363: ! 364: spl0(); ! 365: ! 366: if(lp->kl_temp += lp->kl_cost) { ! 367: lp->kl.l_charge += lp->kl_temp; ! 368: lp->kl_parent->kl_temp += lp->kl_temp; ! 369: lp->kl.l_usage += lp->kl_temp; ! 370: } ! 371: ! 372: lp->kl.l_flags &= ~ACTIVELNODE; ! 373: ! 374: if(lp->kl_parent->kl.l_flags & DEADGROUP) ! 375: lp->kl.l_flags |= DEADGROUP; /* init should pick up group */ ! 376: } ! 377: ! 378: /* ! 379: * Remove lnode from group list. ! 380: */ ! 381: ! 382: remgroup(lp) ! 383: register KL_p lp; ! 384: { ! 385: register KL_p gl, ol; ! 386: ! 387: for(ol = lp->kl_parent, gl = ol->kl_ghead; gl != (KL_p)0; ol = gl, gl = gl->kl_gnext) ! 388: if(gl == lp) { ! 389: /* remove from group list */ ! 390: if(ol == lp->kl_parent) ! 391: ol->kl_ghead = lp->kl_gnext; ! 392: else ! 393: ol->kl_gnext = lp->kl_gnext; ! 394: break; ! 395: } ! 396: ! 397: if(gl==(KL_p)0) panic("remgroup"); ! 398: ! 399: gl = lp->kl_parent; ! 400: ! 401: if(--gl->kl_children == 0 && gl->kl_refcount == 0) ! 402: gl->kl.l_flags |= DEADGROUP; ! 403: ! 404: gl->kl_gshares -= lp->kl.l_shares; ! 405: normshares(gl, 0); ! 406: } ! 407: ! 408: /* ! 409: * Adjust effective shares for group. ! 410: */ ! 411: ! 412: normshares(gl, d) ! 413: register KL_p gl; ! 414: { ! 415: register KL_p lp; ! 416: register float es; ! 417: register float gs; ! 418: ! 419: if((gs = gl->kl_gshares) && !(gl->kl.l_flags & NOTSHARED)) { ! 420: es = gl->kl_eshare * gl->kl.l_shares; ! 421: es /= gs; ! 422: gl->kl_norms = es * es; ! 423: } else if(gl->kl.l_uid == 0) ! 424: gl->kl_norms = onef; ! 425: else ! 426: gl->kl_norms = zerof; ! 427: ! 428: for(lp = gl->kl_ghead; lp != (KL_p)0; lp = lp->kl_gnext) { ! 429: if(gs) { ! 430: es = gl->kl_eshare * lp->kl.l_shares; ! 431: es /= gs; ! 432: } else ! 433: es = zerof; ! 434: ! 435: lp->kl_eshare = es; ! 436: ! 437: if(lp->kl_ghead) { ! 438: if(d >= MAXGROUPS) ! 439: printf("MAXGROUPS(%d) exceeded for group %d\n", MAXGROUPS, lp->kl.l_uid); ! 440: else ! 441: normshares(lp, d+1); ! 442: } else ! 443: lp->kl_norms = es * es; ! 444: } ! 445: } ! 446: ! 447: /* ! 448: * Count group nesting ! 449: */ ! 450: ! 451: grouplevel(gl) ! 452: register KL_p gl; ! 453: { ! 454: register int i; ! 455: ! 456: for(i = 0; (gl = gl->kl_parent) != (KL_p)0; i++); ! 457: return i; ! 458: } ! 459: ! 460: /* ! 461: * Check and set cost dependent variables ! 462: */ ! 463: ! 464: setcosts() ! 465: { ! 466: register int i; ! 467: register float f = onef; ! 468: register float g; ! 469: ! 470: if(MAXUSERS > lnodecnt) ! 471: MAXUSERS = lnodecnt; ! 472: if(MAXGROUPS > (lnodecnt-3)) ! 473: MAXGROUPS = lnodecnt-3; ! 474: if(MAXUSHARE < f) ! 475: MAXUSHARE = f; ! 476: if(MINGSHARE > f) ! 477: MINGSHARE = f; ! 478: ! 479: f -= DecayRate; ! 480: g = PriDecay / (PriDecayBase + (2*NZERO) - 1); ! 481: for(i = 0; i < (2*NZERO); i++) { ! 482: NiceDecays[i] = g * (PriDecayBase + i); ! 483: NiceRates[i] = i <= NZERO ? f : (f * NZERO) / i; ! 484: NiceTicks[i] = (shconsts.sc_tick * ((3*NZERO) - i)) / (2*NZERO); ! 485: } ! 486: ! 487: if(NiceTicks[2*NZERO-1] > 0) ! 488: NiceTicks[2*NZERO-1] = 1; /* nice -19 is almost free */ ! 489: NiceRates[2*NZERO-1] = zerof; ! 490: } ! 491: ! 492: /* ! 493: * Initialise lnodes ! 494: */ ! 495: ! 496: initlnodes(root) ! 497: register KL_p root; ! 498: { ! 499: lastlnode = root; ! 500: MAXUSERS = lnodecnt; ! 501: MaxSharePri = onef; ! 502: ! 503: setcosts(); ! 504: ! 505: root->kl.l_shares = 1; ! 506: root->kl.l_flags = ACTIVELNODE|NOTSHARED; ! 507: root->kl_norms = onef; ! 508: root->kl_eshare = onef; ! 509: root->kl_gshares = zerof; ! 510: root->kl_temp = zerof; ! 511: root->kl_usage = onef; ! 512: root->kl_rate = onef; ! 513: } ! 514: ! 515: /* ! 516: * Adjust usage variables for new value. ! 517: */ ! 518: ! 519: fixusage(lp) ! 520: register KL_p lp; ! 521: { ! 522: register float f; ! 523: ! 524: if(f = lp->kl_norms) { ! 525: if((f = lp->kl.l_usage / f) < twof || (Shareflags & NOSHARE)) ! 526: f = twof; ! 527: if(f > MaxUsage && f < MAXUSAGE) ! 528: MaxUsage = f; ! 529: TotUsage += onef / f; ! 530: lp->kl_usage = f; ! 531: } else ! 532: lp->kl_usage = MAXUSAGE; ! 533: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.