kern_resource.c revision 1.19 1 /*-
2 * Copyright (c) 1982, 1986, 1991, 1993
3 * The Regents of the University of California. 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 8.5 (Berkeley) 1/21/94
39 * $Id: kern_resource.c,v 1.19 1994/05/19 08:13:22 cgd Exp $
40 */
41
42 #include <sys/param.h>
43 #include <sys/kernel.h>
44 #include <sys/file.h>
45 #include <sys/resourcevar.h>
46 #include <sys/malloc.h>
47 #include <sys/proc.h>
48
49 #include <vm/vm.h>
50
51 /*
52 * Resource controls and accounting.
53 */
54
55 struct getpriority_args {
56 int which;
57 int who;
58 };
59 getpriority(curp, uap, retval)
60 struct proc *curp;
61 register struct getpriority_args *uap;
62 int *retval;
63 {
64 register struct proc *p;
65 register int low = PRIO_MAX + 1;
66
67 switch (uap->which) {
68
69 case PRIO_PROCESS:
70 if (uap->who == 0)
71 p = curp;
72 else
73 p = pfind(uap->who);
74 if (p == 0)
75 break;
76 low = p->p_nice;
77 break;
78
79 case PRIO_PGRP: {
80 register struct pgrp *pg;
81
82 if (uap->who == 0)
83 pg = curp->p_pgrp;
84 else if ((pg = pgfind(uap->who)) == NULL)
85 break;
86 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
87 if (p->p_nice < low)
88 low = p->p_nice;
89 }
90 break;
91 }
92
93 case PRIO_USER:
94 if (uap->who == 0)
95 uap->who = curp->p_ucred->cr_uid;
96 for (p = (struct proc *)allproc; p != NULL; p = p->p_next) {
97 if (p->p_ucred->cr_uid == uap->who &&
98 p->p_nice < low)
99 low = p->p_nice;
100 }
101 break;
102
103 default:
104 return (EINVAL);
105 }
106 if (low == PRIO_MAX + 1)
107 return (ESRCH);
108 *retval = low;
109 return (0);
110 }
111
112 struct setpriority_args {
113 int which;
114 int who;
115 int prio;
116 };
117 /* ARGSUSED */
118 setpriority(curp, uap, retval)
119 struct proc *curp;
120 register struct setpriority_args *uap;
121 int *retval;
122 {
123 register struct proc *p;
124 int found = 0, error = 0;
125
126 switch (uap->which) {
127
128 case PRIO_PROCESS:
129 if (uap->who == 0)
130 p = curp;
131 else
132 p = pfind(uap->who);
133 if (p == 0)
134 break;
135 error = donice(curp, p, uap->prio);
136 found++;
137 break;
138
139 case PRIO_PGRP: {
140 register struct pgrp *pg;
141
142 if (uap->who == 0)
143 pg = curp->p_pgrp;
144 else if ((pg = pgfind(uap->who)) == NULL)
145 break;
146 for (p = pg->pg_mem; p != NULL; p = p->p_pgrpnxt) {
147 error = donice(curp, p, uap->prio);
148 found++;
149 }
150 break;
151 }
152
153 case PRIO_USER:
154 if (uap->who == 0)
155 uap->who = curp->p_ucred->cr_uid;
156 for (p = (struct proc *)allproc; p != NULL; p = p->p_next)
157 if (p->p_ucred->cr_uid == uap->who) {
158 error = donice(curp, p, uap->prio);
159 found++;
160 }
161 break;
162
163 default:
164 return (EINVAL);
165 }
166 if (found == 0)
167 return (ESRCH);
168 return (error);
169 }
170
171 donice(curp, chgp, n)
172 register struct proc *curp, *chgp;
173 register int n;
174 {
175 register struct pcred *pcred = curp->p_cred;
176
177 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
178 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
179 pcred->p_ruid != chgp->p_ucred->cr_uid)
180 return (EPERM);
181 if (n > PRIO_MAX)
182 n = PRIO_MAX;
183 if (n < PRIO_MIN)
184 n = PRIO_MIN;
185 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
186 return (EACCES);
187 chgp->p_nice = n;
188 (void)resetpriority(chgp);
189 return (0);
190 }
191
192 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
193 struct osetrlimit_args {
194 u_int which;
195 struct orlimit *lim;
196 };
197 /* ARGSUSED */
198 osetrlimit(p, uap, retval)
199 struct proc *p;
200 struct osetrlimit_args *uap;
201 int *retval;
202 {
203 struct orlimit olim;
204 struct rlimit lim;
205 int error;
206
207 if (error =
208 copyin((caddr_t)uap->lim, (caddr_t)&olim, sizeof (struct orlimit)))
209 return (error);
210 lim.rlim_cur = olim.rlim_cur;
211 lim.rlim_max = olim.rlim_max;
212 return (dosetrlimit(p, uap->which, &lim));
213 }
214
215 struct ogetrlimit_args {
216 u_int which;
217 struct orlimit *rlp;
218 };
219 /* ARGSUSED */
220 ogetrlimit(p, uap, retval)
221 struct proc *p;
222 register struct ogetrlimit_args *uap;
223 int *retval;
224 {
225 struct orlimit olim;
226
227 if (uap->which >= RLIM_NLIMITS)
228 return (EINVAL);
229 olim.rlim_cur = p->p_rlimit[uap->which].rlim_cur;
230 if (olim.rlim_cur == -1)
231 olim.rlim_cur = 0x7fffffff;
232 olim.rlim_max = p->p_rlimit[uap->which].rlim_max;
233 if (olim.rlim_max == -1)
234 olim.rlim_max = 0x7fffffff;
235 return (copyout((caddr_t)&olim, (caddr_t)uap->rlp, sizeof(olim)));
236 }
237 #endif /* COMPAT_43 || COMPAT_SUNOS */
238
239 struct setrlimit_args {
240 u_int which;
241 struct rlimit *lim;
242 };
243 /* ARGSUSED */
244 setrlimit(p, uap, retval)
245 struct proc *p;
246 register struct setrlimit_args *uap;
247 int *retval;
248 {
249 struct rlimit alim;
250 int error;
251
252 if (error =
253 copyin((caddr_t)uap->lim, (caddr_t)&alim, sizeof (struct rlimit)))
254 return (error);
255 return (dosetrlimit(p, uap->which, &alim));
256 }
257
258 int
259 dosetrlimit(p, which, limp)
260 struct proc *p;
261 u_int which;
262 struct rlimit *limp;
263 {
264 register struct rlimit *alimp;
265 extern unsigned maxdmap, maxsmap;
266 int error;
267
268 if (which >= RLIM_NLIMITS)
269 return (EINVAL);
270 alimp = &p->p_rlimit[which];
271 if (limp->rlim_cur > alimp->rlim_max ||
272 limp->rlim_max > alimp->rlim_max)
273 if (error = suser(p->p_ucred, &p->p_acflag))
274 return (error);
275 if (limp->rlim_cur > limp->rlim_max)
276 limp->rlim_cur = limp->rlim_max;
277 if (p->p_limit->p_refcnt > 1 &&
278 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
279 p->p_limit->p_refcnt--;
280 p->p_limit = limcopy(p->p_limit);
281 alimp = &p->p_rlimit[which];
282 }
283
284 switch (which) {
285
286 case RLIMIT_DATA:
287 if (limp->rlim_cur > maxdmap)
288 limp->rlim_cur = maxdmap;
289 if (limp->rlim_max > maxdmap)
290 limp->rlim_max = maxdmap;
291 break;
292
293 case RLIMIT_STACK:
294 if (limp->rlim_cur > maxsmap)
295 limp->rlim_cur = maxsmap;
296 if (limp->rlim_max > maxsmap)
297 limp->rlim_max = maxsmap;
298 /*
299 * Stack is allocated to the max at exec time with only
300 * "rlim_cur" bytes accessible. If stack limit is going
301 * up make more accessible, if going down make inaccessible.
302 */
303 if (limp->rlim_cur != alimp->rlim_cur) {
304 vm_offset_t addr;
305 vm_size_t size;
306 vm_prot_t prot;
307
308 if (limp->rlim_cur > alimp->rlim_cur) {
309 prot = VM_PROT_ALL;
310 size = limp->rlim_cur - alimp->rlim_cur;
311 addr = USRSTACK - limp->rlim_cur;
312 } else {
313 prot = VM_PROT_NONE;
314 size = alimp->rlim_cur - limp->rlim_cur;
315 addr = USRSTACK - alimp->rlim_cur;
316 }
317 addr = trunc_page(addr);
318 size = round_page(size);
319 (void) vm_map_protect(&p->p_vmspace->vm_map,
320 addr, addr+size, prot, FALSE);
321 }
322 break;
323
324 case RLIMIT_NOFILE:
325 if (limp->rlim_cur > maxfiles)
326 limp->rlim_cur = maxfiles;
327 if (limp->rlim_max > maxfiles)
328 limp->rlim_max = maxfiles;
329 break;
330
331 case RLIMIT_NPROC:
332 if (limp->rlim_cur > maxproc)
333 limp->rlim_cur = maxproc;
334 if (limp->rlim_max > maxproc)
335 limp->rlim_max = maxproc;
336 break;
337 }
338 *alimp = *limp;
339 return (0);
340 }
341
342 struct getrlimit_args {
343 u_int which;
344 struct rlimit *rlp;
345 };
346 /* ARGSUSED */
347 getrlimit(p, uap, retval)
348 struct proc *p;
349 register struct getrlimit_args *uap;
350 int *retval;
351 {
352
353 if (uap->which >= RLIM_NLIMITS)
354 return (EINVAL);
355 return (copyout((caddr_t)&p->p_rlimit[uap->which], (caddr_t)uap->rlp,
356 sizeof (struct rlimit)));
357 }
358
359 /*
360 * Transform the running time and tick information in proc p into user,
361 * system, and interrupt time usage.
362 */
363 calcru(p, up, sp, ip)
364 register struct proc *p;
365 register struct timeval *up;
366 register struct timeval *sp;
367 register struct timeval *ip;
368 {
369 register u_quad_t u, st, ut, it, tot;
370 register u_long sec, usec;
371 register int s;
372 struct timeval tv;
373
374 s = splstatclock();
375 st = p->p_sticks;
376 ut = p->p_uticks;
377 it = p->p_iticks;
378 splx(s);
379
380 tot = st + ut + it;
381 if (tot == 0) {
382 up->tv_sec = up->tv_usec = 0;
383 sp->tv_sec = sp->tv_usec = 0;
384 if (ip != NULL)
385 ip->tv_sec = ip->tv_usec = 0;
386 return;
387 }
388
389 sec = p->p_rtime.tv_sec;
390 usec = p->p_rtime.tv_usec;
391 if (p == curproc) {
392 /*
393 * Adjust for the current time slice. This is actually fairly
394 * important since the error here is on the order of a time
395 * quantum, which is much greater than the sampling error.
396 */
397 microtime(&tv);
398 sec += tv.tv_sec - runtime.tv_sec;
399 usec += tv.tv_usec - runtime.tv_usec;
400 }
401 u = sec * 1000000 + usec;
402 st = (u * st) / tot;
403 sp->tv_sec = st / 1000000;
404 sp->tv_usec = st % 1000000;
405 ut = (u * ut) / tot;
406 up->tv_sec = ut / 1000000;
407 up->tv_usec = ut % 1000000;
408 if (ip != NULL) {
409 it = (u * it) / tot;
410 ip->tv_sec = it / 1000000;
411 ip->tv_usec = it % 1000000;
412 }
413 }
414
415 struct getrusage_args {
416 int who;
417 struct rusage *rusage;
418 };
419 /* ARGSUSED */
420 getrusage(p, uap, retval)
421 register struct proc *p;
422 register struct getrusage_args *uap;
423 int *retval;
424 {
425 register struct rusage *rup;
426
427 switch (uap->who) {
428
429 case RUSAGE_SELF:
430 rup = &p->p_stats->p_ru;
431 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
432 break;
433
434 case RUSAGE_CHILDREN:
435 rup = &p->p_stats->p_cru;
436 break;
437
438 default:
439 return (EINVAL);
440 }
441 return (copyout((caddr_t)rup, (caddr_t)uap->rusage,
442 sizeof (struct rusage)));
443 }
444
445 ruadd(ru, ru2)
446 register struct rusage *ru, *ru2;
447 {
448 register long *ip, *ip2;
449 register int i;
450
451 timevaladd(&ru->ru_utime, &ru2->ru_utime);
452 timevaladd(&ru->ru_stime, &ru2->ru_stime);
453 if (ru->ru_maxrss < ru2->ru_maxrss)
454 ru->ru_maxrss = ru2->ru_maxrss;
455 ip = &ru->ru_first; ip2 = &ru2->ru_first;
456 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
457 *ip++ += *ip2++;
458 }
459
460 /*
461 * Make a copy of the plimit structure.
462 * We share these structures copy-on-write after fork,
463 * and copy when a limit is changed.
464 */
465 struct plimit *
466 limcopy(lim)
467 struct plimit *lim;
468 {
469 register struct plimit *copy;
470
471 MALLOC(copy, struct plimit *, sizeof(struct plimit),
472 M_SUBPROC, M_WAITOK);
473 bcopy(lim->pl_rlimit, copy->pl_rlimit,
474 sizeof(struct rlimit) * RLIM_NLIMITS);
475 copy->p_lflags = 0;
476 copy->p_refcnt = 1;
477 return (copy);
478 }
479