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