kern_resource.c revision 1.18 1 /*-
2 * Copyright (c) 1982, 1986, 1991 The Regents of the University of California.
3 * All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * from: @(#)kern_resource.c 7.13 (Berkeley) 5/9/91
39 * $Id: kern_resource.c,v 1.18 1994/05/18 05:12:39 cgd Exp $
40 */
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/resourcevar.h>
46 #include <sys/malloc.h>
47 #include <sys/proc.h>
48
49 #include <vm/vm.h>
50
51 int dosetrlimit __P((struct proc *p, u_int which, struct rlimit *limp));
52
53 /*
54 * Resource controls and accounting.
55 */
56
57 struct getpriority_args {
58 int which;
59 int who;
60 };
61
62 int
63 getpriority(curp, uap, retval)
64 struct proc *curp;
65 register struct getpriority_args *uap;
66 int *retval;
67 {
68 register struct proc *p;
69 register int low = PRIO_MAX + 1;
70
71 switch (uap->which) {
72
73 case PRIO_PROCESS:
74 if (uap->who == 0)
75 p = curp;
76 else
77 p = pfind(uap->who);
78 if (p == 0)
79 break;
80 low = p->p_nice;
81 break;
82
83 case PRIO_PGRP: {
84 register struct pgrp *pg;
85
86 if (uap->who == 0)
87 pg = curp->p_pgrp;
88 else if ((pg = pgfind(uap->who)) == NULL)
89 break;
90 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
91 if (p->p_nice < low)
92 low = p->p_nice;
93 }
94 break;
95 }
96
97 case PRIO_USER:
98 if (uap->who == 0)
99 uap->who = curp->p_ucred->cr_uid;
100 for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
101 if (p->p_ucred->cr_uid == uap->who &&
102 p->p_nice < low)
103 low = p->p_nice;
104 }
105 break;
106
107 default:
108 return (EINVAL);
109 }
110 if (low == PRIO_MAX + 1)
111 return (ESRCH);
112 *retval = low;
113 return (0);
114 }
115
116 struct setpriority_args {
117 int which;
118 int who;
119 int prio;
120 };
121
122 /* ARGSUSED */
123 int
124 setpriority(curp, uap, retval)
125 struct proc *curp;
126 register struct setpriority_args *uap;
127 int *retval;
128 {
129 register struct proc *p;
130 int found = 0, error = 0;
131
132 switch (uap->which) {
133
134 case PRIO_PROCESS:
135 if (uap->who == 0)
136 p = curp;
137 else
138 p = pfind(uap->who);
139 if (p == 0)
140 break;
141 error = donice(curp, p, uap->prio);
142 found++;
143 break;
144
145 case PRIO_PGRP: {
146 register struct pgrp *pg;
147
148 if (uap->who == 0)
149 pg = curp->p_pgrp;
150 else if ((pg = pgfind(uap->who)) == NULL)
151 break;
152 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
153 error = donice(curp, p, uap->prio);
154 found++;
155 }
156 break;
157 }
158
159 case PRIO_USER:
160 if (uap->who == 0)
161 uap->who = curp->p_ucred->cr_uid;
162 for (p = (struct proc *)allproc; p != NULL; p = p->p_next)
163 if (p->p_ucred->cr_uid == uap->who) {
164 error = donice(curp, p, uap->prio);
165 found++;
166 }
167 break;
168
169 default:
170 return (EINVAL);
171 }
172 if (found == 0)
173 return (ESRCH);
174 return (error);
175 }
176
177 int
178 donice(curp, chgp, n)
179 register struct proc *curp, *chgp;
180 register int n;
181 {
182 register struct pcred *pcred = curp->p_cred;
183
184 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
185 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
186 pcred->p_ruid != chgp->p_ucred->cr_uid)
187 return (EPERM);
188 if (n > PRIO_MAX)
189 n = PRIO_MAX;
190 if (n < PRIO_MIN)
191 n = PRIO_MIN;
192 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
193 return (EACCES);
194 chgp->p_nice = n;
195 (void) resetpriority(chgp);
196 return (0);
197 }
198
199 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
200 struct osetrlimit_args {
201 u_int which;
202 struct orlimit *lim;
203 };
204 /* ARGSUSED */
205 int
206 osetrlimit(p, uap, retval)
207 struct proc *p;
208 struct osetrlimit_args *uap;
209 int *retval;
210 {
211 struct orlimit olim;
212 struct rlimit lim;
213 int error;
214
215 if (error = copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof(olim)))
216 return (error);
217 lim.rlim_cur = olim.rlim_cur;
218 lim.rlim_max = olim.rlim_max;
219 return (dosetrlimit(p, uap->which, &lim));
220 }
221
222 struct ogetrlimit_args {
223 u_int which;
224 struct orlimit *rlp;
225 };
226 /* ARGSUSED */
227 int
228 ogetrlimit(p, uap, retval)
229 struct proc *p;
230 register struct ogetrlimit_args *uap;
231 int *retval;
232 {
233 struct orlimit olim;
234
235 if (uap->which >= RLIM_NLIMITS)
236 return (EINVAL);
237 olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
238 if (olim.rlim_cur == -1)
239 olim.rlim_cur = 0x7fffffff;
240 olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
241 if (olim.rlim_max == -1)
242 olim.rlim_max = 0x7fffffff;
243 return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
244 }
245 #endif
246
247 struct setrlimit_args {
248 u_int which;
249 struct rlimit *lim;
250 };
251
252 /* ARGSUSED */
253 int
254 setrlimit(p, uap, retval)
255 struct proc *p;
256 register struct setrlimit_args *uap;
257 int *retval;
258 {
259 struct rlimit lim;
260 int error;
261
262 if (error = copyin((caddr_t)uap->lim, (caddr_t)&lim, sizeof(lim)))
263 return (error);
264 return (dosetrlimit(p, uap->which, &lim));
265 }
266
267 int
268 dosetrlimit(p, which, limp)
269 struct proc *p;
270 u_int which;
271 struct rlimit *limp;
272 {
273 register struct rlimit *alimp;
274 extern int maxfdescs;
275 int error;
276
277 if (which >= RLIM_NLIMITS)
278 return (EINVAL);
279 alimp = &p->p_rlimit[which];
280 if (limp->rlim_cur > alimp->rlim_max ||
281 limp->rlim_max > alimp->rlim_max)
282 if (error = suser(p->p_ucred, &p->p_acflag))
283 return (error);
284 if (limp->rlim_cur > limp->rlim_max)
285 limp->rlim_cur = limp->rlim_max;
286 if (p->p_limit->p_refcnt > 1 &&
287 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
288 p->p_limit->p_refcnt--;
289 p->p_limit = limcopy(p->p_limit);
290 alimp = &p->p_rlimit[which];
291 }
292
293 switch (which) {
294
295 case RLIMIT_DATA:
296 if (limp->rlim_cur > MAXDSIZ)
297 limp->rlim_cur = MAXDSIZ;
298 if (limp->rlim_max > MAXDSIZ)
299 limp->rlim_max = MAXDSIZ;
300 break;
301
302 case RLIMIT_NOFILE:
303 if (limp->rlim_cur > maxfdescs)
304 limp->rlim_cur = maxfdescs;
305 if (limp->rlim_max > maxfdescs)
306 limp->rlim_max = maxfdescs;
307 break;
308
309 case RLIMIT_STACK:
310 if (limp->rlim_cur > MAXSSIZ)
311 limp->rlim_cur = MAXSSIZ;
312 if (limp->rlim_max > MAXSSIZ)
313 limp->rlim_max = MAXSSIZ;
314 /*
315 * Stack is allocated to the max at exec time with only
316 * "rlim_cur" bytes accessible. If stack limit is going
317 * up make more accessible, if going down make inaccessible.
318 */
319 if (limp->rlim_cur != alimp->rlim_cur) {
320 vm_offset_t addr;
321 vm_size_t size;
322 vm_prot_t prot;
323
324 if (limp->rlim_cur > alimp->rlim_cur) {
325 prot = VM_PROT_ALL;
326 size = limp->rlim_cur - alimp->rlim_cur;
327 addr = USRSTACK - limp->rlim_cur;
328 } else {
329 prot = VM_PROT_NONE;
330 size = alimp->rlim_cur - limp->rlim_cur;
331 addr = USRSTACK - alimp->rlim_cur;
332 }
333 addr = trunc_page(addr);
334 size = round_page(size);
335 (void) vm_map_protect(&p->p_vmspace->vm_map,
336 addr, addr+size, prot, FALSE);
337 }
338 break;
339 }
340 *alimp = *limp;
341 return (0);
342 }
343
344 struct getrlimit_args {
345 u_int which;
346 struct rlimit *rlp;
347 };
348
349 /* ARGSUSED */
350 int
351 getrlimit(p, uap, retval)
352 struct proc *p;
353 register struct getrlimit_args *uap;
354 int *retval;
355 {
356
357 if (uap->which >= RLIM_NLIMITS)
358 return (EINVAL);
359 return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
360 sizeof (struct rlimit)));
361 }
362
363 /*
364 * Transform the running time and tick information in proc p into user,
365 * system, and interrupt time usage.
366 */
367 calcru(p, up, sp, ip)
368 register struct proc *p;
369 register struct timeval *up;
370 register struct timeval *sp;
371 register struct timeval *ip;
372 {
373 register u_quad_t u, st, ut, it, tot;
374 register u_long sec, usec;
375 register int s;
376 struct timeval tv;
377
378 s = splstatclock();
379 st = p->p_sticks;
380 ut = p->p_uticks;
381 it = p->p_iticks;
382 splx(s);
383
384 tot = st + ut + it;
385 if (tot == 0) {
386 up->tv_sec = up->tv_usec = 0;
387 sp->tv_sec = sp->tv_usec = 0;
388 if (ip != NULL)
389 ip->tv_sec = ip->tv_usec = 0;
390 return;
391 }
392
393 sec = p->p_rtime.tv_sec;
394 usec = p->p_rtime.tv_usec;
395 if (p == curproc) {
396 /*
397 * Adjust for the current time slice. This is actually fairly
398 * important since the error here is on the order of a time
399 * quantum, which is much greater than the sampling error.
400 */
401 microtime(&tv);
402 sec += tv.tv_sec - runtime.tv_sec;
403 usec += tv.tv_usec - runtime.tv_usec;
404 }
405 u = sec * 1000000 + usec;
406 st = (u * st) / tot;
407 sp->tv_sec = st / 1000000;
408 sp->tv_usec = st % 1000000;
409 ut = (u * ut) / tot;
410 up->tv_sec = ut / 1000000;
411 up->tv_usec = ut % 1000000;
412 if (ip != NULL) {
413 it = (u * it) / tot;
414 ip->tv_sec = it / 1000000;
415 ip->tv_usec = it % 1000000;
416 }
417 }
418
419 struct getrusage_args {
420 int who;
421 struct rusage *rusage;
422 };
423 /* ARGSUSED */
424 int
425 getrusage(p, uap, retval)
426 register struct proc *p;
427 register struct getrusage_args *uap;
428 int *retval;
429 {
430 register struct rusage *rup;
431
432 switch (uap->who) {
433
434 case RUSAGE_SELF: {
435 rup = &p->p_stats->p_ru;
436 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
437 break;
438 }
439
440 case RUSAGE_CHILDREN:
441 rup = &p->p_stats->p_cru;
442 break;
443
444 default:
445 return (EINVAL);
446 }
447 return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
448 sizeof (struct rusage)));
449 }
450
451 void
452 ruadd(ru, ru2)
453 register struct rusage *ru, *ru2;
454 {
455 register long *ip, *ip2;
456 register int i;
457
458 timevaladd(&ru->ru_utime, &ru2->ru_utime);
459 timevaladd(&ru->ru_stime, &ru2->ru_stime);
460 if (ru->ru_maxrss < ru2->ru_maxrss)
461 ru->ru_maxrss = ru2->ru_maxrss;
462 ip = &ru->ru_first; ip2 = &ru2->ru_first;
463 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
464 *ip++ += *ip2++;
465 }
466
467 /*
468 * Make a copy of the plimit structure.
469 * We share these structures copy-on-write after fork,
470 * and copy when a limit is changed.
471 */
472 struct plimit *
473 limcopy(lim)
474 struct plimit *lim;
475 {
476 register struct plimit *copy;
477
478 MALLOC(copy, struct plimit *, sizeof(struct plimit),
479 M_SUBPROC, M_WAITOK);
480 bcopy(lim->pl_rlimit, copy->pl_rlimit,
481 sizeof(struct rlimit) * RLIM_NLIMITS);
482 copy->p_lflags = 0;
483 copy->p_refcnt = 1;
484 return (copy);
485 }
486