Annotation of sys/kern/kern_resource.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: kern_resource.c,v 1.32 2007/04/12 22:14:15 tedu Exp $ */
2: /* $NetBSD: kern_resource.c,v 1.38 1996/10/23 07:19:38 matthias Exp $ */
3:
4: /*-
5: * Copyright (c) 1982, 1986, 1991, 1993
6: * The Regents of the University of California. All rights reserved.
7: * (c) UNIX System Laboratories, Inc.
8: * All or some portions of this file are derived from material licensed
9: * to the University of California by American Telephone and Telegraph
10: * Co. or Unix System Laboratories, Inc. and are reproduced herein with
11: * the permission of UNIX System Laboratories, Inc.
12: *
13: * Redistribution and use in source and binary forms, with or without
14: * modification, are permitted provided that the following conditions
15: * are met:
16: * 1. Redistributions of source code must retain the above copyright
17: * notice, this list of conditions and the following disclaimer.
18: * 2. Redistributions in binary form must reproduce the above copyright
19: * notice, this list of conditions and the following disclaimer in the
20: * documentation and/or other materials provided with the distribution.
21: * 3. Neither the name of the University nor the names of its contributors
22: * may be used to endorse or promote products derived from this software
23: * without specific prior written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35: * SUCH DAMAGE.
36: *
37: * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94
38: */
39:
40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/kernel.h>
43: #include <sys/file.h>
44: #include <sys/resourcevar.h>
45: #include <sys/pool.h>
46: #include <sys/proc.h>
47: #include <sys/sched.h>
48:
49: #include <sys/mount.h>
50: #include <sys/syscallargs.h>
51:
52: #include <uvm/uvm_extern.h>
53:
54: /*
55: * Patchable maximum data and stack limits.
56: */
57: rlim_t maxdmap = MAXDSIZ;
58: rlim_t maxsmap = MAXSSIZ;
59:
60: /*
61: * Resource controls and accounting.
62: */
63:
64: int
65: sys_getpriority(struct proc *curp, void *v, register_t *retval)
66: {
67: struct sys_getpriority_args /* {
68: syscallarg(int) which;
69: syscallarg(id_t) who;
70: } */ *uap = v;
71: struct proc *p;
72: int low = NZERO + PRIO_MAX + 1;
73:
74: switch (SCARG(uap, which)) {
75:
76: case PRIO_PROCESS:
77: if (SCARG(uap, who) == 0)
78: p = curp;
79: else
80: p = pfind(SCARG(uap, who));
81: if (p == 0)
82: break;
83: low = p->p_nice;
84: break;
85:
86: case PRIO_PGRP: {
87: struct pgrp *pg;
88:
89: if (SCARG(uap, who) == 0)
90: pg = curp->p_pgrp;
91: else if ((pg = pgfind(SCARG(uap, who))) == NULL)
92: break;
93: LIST_FOREACH(p, &pg->pg_members, p_pglist) {
94: if (p->p_nice < low)
95: low = p->p_nice;
96: }
97: break;
98: }
99:
100: case PRIO_USER:
101: if (SCARG(uap, who) == 0)
102: SCARG(uap, who) = curp->p_ucred->cr_uid;
103: for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list))
104: if (p->p_ucred->cr_uid == SCARG(uap, who) &&
105: p->p_nice < low)
106: low = p->p_nice;
107: break;
108:
109: default:
110: return (EINVAL);
111: }
112: if (low == NZERO + PRIO_MAX + 1)
113: return (ESRCH);
114: *retval = low - NZERO;
115: return (0);
116: }
117:
118: /* ARGSUSED */
119: int
120: sys_setpriority(struct proc *curp, void *v, register_t *retval)
121: {
122: struct sys_setpriority_args /* {
123: syscallarg(int) which;
124: syscallarg(id_t) who;
125: syscallarg(int) prio;
126: } */ *uap = v;
127: struct proc *p;
128: int found = 0, error = 0;
129:
130: switch (SCARG(uap, which)) {
131:
132: case PRIO_PROCESS:
133: if (SCARG(uap, who) == 0)
134: p = curp;
135: else
136: p = pfind(SCARG(uap, who));
137: if (p == 0)
138: break;
139: error = donice(curp, p, SCARG(uap, prio));
140: found++;
141: break;
142:
143: case PRIO_PGRP: {
144: struct pgrp *pg;
145:
146: if (SCARG(uap, who) == 0)
147: pg = curp->p_pgrp;
148: else if ((pg = pgfind(SCARG(uap, who))) == NULL)
149: break;
150: LIST_FOREACH(p, &pg->pg_members, p_pglist) {
151: error = donice(curp, p, SCARG(uap, prio));
152: found++;
153: }
154: break;
155: }
156:
157: case PRIO_USER:
158: if (SCARG(uap, who) == 0)
159: SCARG(uap, who) = curp->p_ucred->cr_uid;
160: for (p = LIST_FIRST(&allproc); p; p = LIST_NEXT(p, p_list))
161: if (p->p_ucred->cr_uid == SCARG(uap, who)) {
162: error = donice(curp, p, SCARG(uap, prio));
163: found++;
164: }
165: break;
166:
167: default:
168: return (EINVAL);
169: }
170: if (found == 0)
171: return (ESRCH);
172: return (error);
173: }
174:
175: int
176: donice(struct proc *curp, struct proc *chgp, int n)
177: {
178: struct pcred *pcred = curp->p_cred;
179: int s;
180:
181: if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
182: pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
183: pcred->p_ruid != chgp->p_ucred->cr_uid)
184: return (EPERM);
185: if (n > PRIO_MAX)
186: n = PRIO_MAX;
187: if (n < PRIO_MIN)
188: n = PRIO_MIN;
189: n += NZERO;
190: if (n < chgp->p_nice && suser(curp, 0))
191: return (EACCES);
192: chgp->p_nice = n;
193: SCHED_LOCK(s);
194: (void)resetpriority(chgp);
195: SCHED_UNLOCK(s);
196: return (0);
197: }
198:
199: /* ARGSUSED */
200: int
201: sys_setrlimit(struct proc *p, void *v, register_t *retval)
202: {
203: struct sys_setrlimit_args /* {
204: syscallarg(int) which;
205: syscallarg(const struct rlimit *) rlp;
206: } */ *uap = v;
207: struct rlimit alim;
208: int error;
209:
210: error = copyin((caddr_t)SCARG(uap, rlp), (caddr_t)&alim,
211: sizeof (struct rlimit));
212: if (error)
213: return (error);
214: return (dosetrlimit(p, SCARG(uap, which), &alim));
215: }
216:
217: int
218: dosetrlimit(struct proc *p, u_int which, struct rlimit *limp)
219: {
220: struct rlimit *alimp;
221: rlim_t maxlim;
222: int error;
223:
224: if (which >= RLIM_NLIMITS)
225: return (EINVAL);
226:
227: alimp = &p->p_rlimit[which];
228: if (limp->rlim_cur > alimp->rlim_max ||
229: limp->rlim_max > alimp->rlim_max)
230: if ((error = suser(p, 0)) != 0)
231: return (error);
232: if (p->p_p->ps_limit->p_refcnt > 1 &&
233: (p->p_p->ps_limit->p_lflags & PL_SHAREMOD) == 0) {
234: p->p_p->ps_limit->p_refcnt--;
235: p->p_p->ps_limit = limcopy(p->p_p->ps_limit);
236: alimp = &p->p_rlimit[which];
237: }
238:
239: switch (which) {
240: case RLIMIT_DATA:
241: maxlim = maxdmap;
242: break;
243: case RLIMIT_STACK:
244: maxlim = maxsmap;
245: break;
246: case RLIMIT_NOFILE:
247: maxlim = maxfiles;
248: break;
249: case RLIMIT_NPROC:
250: maxlim = maxproc;
251: break;
252: default:
253: maxlim = RLIM_INFINITY;
254: break;
255: }
256:
257: if (limp->rlim_max > maxlim)
258: limp->rlim_max = maxlim;
259: if (limp->rlim_cur > limp->rlim_max)
260: limp->rlim_cur = limp->rlim_max;
261:
262: if (which == RLIMIT_STACK) {
263: /*
264: * Stack is allocated to the max at exec time with only
265: * "rlim_cur" bytes accessible. If stack limit is going
266: * up make more accessible, if going down make inaccessible.
267: */
268: if (limp->rlim_cur != alimp->rlim_cur) {
269: vaddr_t addr;
270: vsize_t size;
271: vm_prot_t prot;
272:
273: if (limp->rlim_cur > alimp->rlim_cur) {
274: prot = VM_PROT_READ|VM_PROT_WRITE;
275: size = limp->rlim_cur - alimp->rlim_cur;
276: #ifdef MACHINE_STACK_GROWS_UP
277: addr = USRSTACK + alimp->rlim_cur;
278: #else
279: addr = USRSTACK - limp->rlim_cur;
280: #endif
281: } else {
282: prot = VM_PROT_NONE;
283: size = alimp->rlim_cur - limp->rlim_cur;
284: #ifdef MACHINE_STACK_GROWS_UP
285: addr = USRSTACK + limp->rlim_cur;
286: #else
287: addr = USRSTACK - alimp->rlim_cur;
288: #endif
289: }
290: addr = trunc_page(addr);
291: size = round_page(size);
292: (void) uvm_map_protect(&p->p_vmspace->vm_map,
293: addr, addr+size, prot, FALSE);
294: }
295: }
296:
297: *alimp = *limp;
298: return (0);
299: }
300:
301: /* ARGSUSED */
302: int
303: sys_getrlimit(struct proc *p, void *v, register_t *retval)
304: {
305: struct sys_getrlimit_args /* {
306: syscallarg(int) which;
307: syscallarg(struct rlimit *) rlp;
308: } */ *uap = v;
309:
310: if (SCARG(uap, which) < 0 || SCARG(uap, which) >= RLIM_NLIMITS)
311: return (EINVAL);
312: return (copyout((caddr_t)&p->p_rlimit[SCARG(uap, which)],
313: (caddr_t)SCARG(uap, rlp), sizeof (struct rlimit)));
314: }
315:
316: /*
317: * Transform the running time and tick information in proc p into user,
318: * system, and interrupt time usage.
319: */
320: void
321: calcru(struct proc *p, struct timeval *up, struct timeval *sp,
322: struct timeval *ip)
323: {
324: u_quad_t st, ut, it;
325: int freq;
326: int s;
327:
328: s = splstatclock();
329: st = p->p_sticks;
330: ut = p->p_uticks;
331: it = p->p_iticks;
332: splx(s);
333:
334: if (st + ut + it == 0) {
335: timerclear(up);
336: timerclear(sp);
337: if (ip != NULL)
338: timerclear(ip);
339: return;
340: }
341:
342: freq = stathz ? stathz : hz;
343:
344: st = st * 1000000 / freq;
345: sp->tv_sec = st / 1000000;
346: sp->tv_usec = st % 1000000;
347: ut = ut * 1000000 / freq;
348: up->tv_sec = ut / 1000000;
349: up->tv_usec = ut % 1000000;
350: if (ip != NULL) {
351: it = it * 1000000 / freq;
352: ip->tv_sec = it / 1000000;
353: ip->tv_usec = it % 1000000;
354: }
355: }
356:
357: /* ARGSUSED */
358: int
359: sys_getrusage(struct proc *p, void *v, register_t *retval)
360: {
361: struct sys_getrusage_args /* {
362: syscallarg(int) who;
363: syscallarg(struct rusage *) rusage;
364: } */ *uap = v;
365: struct rusage *rup;
366:
367: switch (SCARG(uap, who)) {
368:
369: case RUSAGE_SELF:
370: rup = &p->p_stats->p_ru;
371: calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
372: break;
373:
374: case RUSAGE_CHILDREN:
375: rup = &p->p_stats->p_cru;
376: break;
377:
378: default:
379: return (EINVAL);
380: }
381: return (copyout((caddr_t)rup, (caddr_t)SCARG(uap, rusage),
382: sizeof (struct rusage)));
383: }
384:
385: void
386: ruadd(struct rusage *ru, struct rusage *ru2)
387: {
388: long *ip, *ip2;
389: int i;
390:
391: timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
392: timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
393: if (ru->ru_maxrss < ru2->ru_maxrss)
394: ru->ru_maxrss = ru2->ru_maxrss;
395: ip = &ru->ru_first; ip2 = &ru2->ru_first;
396: for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
397: *ip++ += *ip2++;
398: }
399:
400: struct pool plimit_pool;
401:
402: /*
403: * Make a copy of the plimit structure.
404: * We share these structures copy-on-write after fork,
405: * and copy when a limit is changed.
406: */
407: struct plimit *
408: limcopy(struct plimit *lim)
409: {
410: struct plimit *newlim;
411: static int initialized;
412:
413: if (!initialized) {
414: pool_init(&plimit_pool, sizeof(struct plimit), 0, 0, 0,
415: "plimitpl", &pool_allocator_nointr);
416: initialized = 1;
417: }
418:
419: newlim = pool_get(&plimit_pool, PR_WAITOK);
420: bcopy(lim->pl_rlimit, newlim->pl_rlimit,
421: sizeof(struct rlimit) * RLIM_NLIMITS);
422: newlim->p_lflags = 0;
423: newlim->p_refcnt = 1;
424: return (newlim);
425: }
426:
427: void
428: limfree(struct plimit *lim)
429: {
430: if (--lim->p_refcnt > 0)
431: return;
432: pool_put(&plimit_pool, lim);
433: }
CVSweb