|
|
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.