kern_resource.c revision 1.60.2.4 1 /* $NetBSD: kern_resource.c,v 1.60.2.4 2002/05/29 21:33:12 nathanw 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.8 (Berkeley) 2/14/95
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: kern_resource.c,v 1.60.2.4 2002/05/29 21:33:12 nathanw Exp $");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/file.h>
50 #include <sys/resourcevar.h>
51 #include <sys/malloc.h>
52 #include <sys/pool.h>
53 #include <sys/lwp.h>
54 #include <sys/proc.h>
55
56 #include <sys/mount.h>
57 #include <sys/sa.h>
58 #include <sys/syscallargs.h>
59
60 #include <uvm/uvm_extern.h>
61
62 /*
63 * Maximum process data and stack limits.
64 * They are variables so they are patchable.
65 *
66 * XXXX Do we really need them to be patchable?
67 */
68 rlim_t maxdmap = MAXDSIZ;
69 rlim_t maxsmap = MAXSSIZ;
70
71 /*
72 * Resource controls and accounting.
73 */
74
75 int
76 sys_getpriority(l, v, retval)
77 struct lwp *l;
78 void *v;
79 register_t *retval;
80 {
81 struct sys_getpriority_args /* {
82 syscallarg(int) which;
83 syscallarg(int) who;
84 } */ *uap = v;
85 struct proc *curp = l->l_proc, *p;
86 int low = NZERO + PRIO_MAX + 1;
87
88 switch (SCARG(uap, which)) {
89
90 case PRIO_PROCESS:
91 if (SCARG(uap, who) == 0)
92 p = curp;
93 else
94 p = pfind(SCARG(uap, who));
95 if (p == 0)
96 break;
97 low = p->p_nice;
98 break;
99
100 case PRIO_PGRP: {
101 struct pgrp *pg;
102
103 if (SCARG(uap, who) == 0)
104 pg = curp->p_pgrp;
105 else if ((pg = pgfind(SCARG(uap, who))) == NULL)
106 break;
107 for (p = pg->pg_members.lh_first; p != 0;
108 p = p->p_pglist.le_next) {
109 if (p->p_nice < low)
110 low = p->p_nice;
111 }
112 break;
113 }
114
115 case PRIO_USER:
116 if (SCARG(uap, who) == 0)
117 SCARG(uap, who) = curp->p_ucred->cr_uid;
118 proclist_lock_read();
119 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
120 if (p->p_ucred->cr_uid == SCARG(uap, who) &&
121 p->p_nice < low)
122 low = p->p_nice;
123 proclist_unlock_read();
124 break;
125
126 default:
127 return (EINVAL);
128 }
129 if (low == NZERO + PRIO_MAX + 1)
130 return (ESRCH);
131 *retval = low - NZERO;
132 return (0);
133 }
134
135 /* ARGSUSED */
136 int
137 sys_setpriority(l, v, retval)
138 struct lwp *l;
139 void *v;
140 register_t *retval;
141 {
142 struct sys_setpriority_args /* {
143 syscallarg(int) which;
144 syscallarg(int) who;
145 syscallarg(int) prio;
146 } */ *uap = v;
147 struct proc *curp = l->l_proc, *p;
148 int found = 0, error = 0;
149
150 switch (SCARG(uap, which)) {
151
152 case PRIO_PROCESS:
153 if (SCARG(uap, who) == 0)
154 p = curp;
155 else
156 p = pfind(SCARG(uap, who));
157 if (p == 0)
158 break;
159 error = donice(curp, p, SCARG(uap, prio));
160 found++;
161 break;
162
163 case PRIO_PGRP: {
164 struct pgrp *pg;
165
166 if (SCARG(uap, who) == 0)
167 pg = curp->p_pgrp;
168 else if ((pg = pgfind(SCARG(uap, who))) == NULL)
169 break;
170 for (p = pg->pg_members.lh_first; p != 0;
171 p = p->p_pglist.le_next) {
172 error = donice(curp, p, SCARG(uap, prio));
173 found++;
174 }
175 break;
176 }
177
178 case PRIO_USER:
179 if (SCARG(uap, who) == 0)
180 SCARG(uap, who) = curp->p_ucred->cr_uid;
181 proclist_lock_read();
182 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next)
183 if (p->p_ucred->cr_uid == SCARG(uap, who)) {
184 error = donice(curp, p, SCARG(uap, prio));
185 found++;
186 }
187 proclist_unlock_read();
188 break;
189
190 default:
191 return (EINVAL);
192 }
193 if (found == 0)
194 return (ESRCH);
195 return (error);
196 }
197
198 int
199 donice(curp, chgp, n)
200 struct proc *curp, *chgp;
201 int n;
202 {
203 struct pcred *pcred = curp->p_cred;
204 int s;
205
206 if (pcred->pc_ucred->cr_uid && pcred->p_ruid &&
207 pcred->pc_ucred->cr_uid != chgp->p_ucred->cr_uid &&
208 pcred->p_ruid != chgp->p_ucred->cr_uid)
209 return (EPERM);
210 if (n > PRIO_MAX)
211 n = PRIO_MAX;
212 if (n < PRIO_MIN)
213 n = PRIO_MIN;
214 n += NZERO;
215 if (n < chgp->p_nice && suser(pcred->pc_ucred, &curp->p_acflag))
216 return (EACCES);
217 chgp->p_nice = n;
218 SCHED_LOCK(s);
219 (void)resetprocpriority(chgp);
220 SCHED_UNLOCK(s);
221 return (0);
222 }
223
224 /* ARGSUSED */
225 int
226 sys_setrlimit(l, v, retval)
227 struct lwp *l;
228 void *v;
229 register_t *retval;
230 {
231 struct sys_setrlimit_args /* {
232 syscallarg(int) which;
233 syscallarg(const struct rlimit *) rlp;
234 } */ *uap = v;
235 struct proc *p = l->l_proc;
236 int which = SCARG(uap, which);
237 struct rlimit alim;
238 int error;
239
240 error = copyin(SCARG(uap, rlp), &alim, sizeof(struct rlimit));
241 if (error)
242 return (error);
243 return (dosetrlimit(p, p->p_cred, which, &alim));
244 }
245
246 int
247 dosetrlimit(p, cred, which, limp)
248 struct proc *p;
249 struct pcred *cred;
250 int which;
251 struct rlimit *limp;
252 {
253 struct rlimit *alimp;
254 struct plimit *newplim;
255 int error;
256
257 if ((u_int)which >= RLIM_NLIMITS)
258 return (EINVAL);
259
260 if (limp->rlim_cur < 0 || limp->rlim_max < 0)
261 return (EINVAL);
262
263 alimp = &p->p_rlimit[which];
264 /* if we don't change the value, no need to limcopy() */
265 if (limp->rlim_cur == alimp->rlim_cur &&
266 limp->rlim_max == alimp->rlim_max)
267 return 0;
268
269 if (limp->rlim_cur > limp->rlim_max) {
270 /*
271 * This is programming error. According to SUSv2, we should
272 * return error in this case.
273 */
274 return (EINVAL);
275 }
276 if (limp->rlim_max > alimp->rlim_max
277 && (error = suser(cred->pc_ucred, &p->p_acflag)) != 0)
278 return (error);
279
280 if (p->p_limit->p_refcnt > 1 &&
281 (p->p_limit->p_lflags & PL_SHAREMOD) == 0) {
282 newplim = limcopy(p->p_limit);
283 limfree(p->p_limit);
284 p->p_limit = newplim;
285 alimp = &p->p_rlimit[which];
286 }
287
288 switch (which) {
289
290 case RLIMIT_DATA:
291 if (limp->rlim_cur > maxdmap)
292 limp->rlim_cur = maxdmap;
293 if (limp->rlim_max > maxdmap)
294 limp->rlim_max = maxdmap;
295 break;
296
297 case RLIMIT_STACK:
298 if (limp->rlim_cur > maxsmap)
299 limp->rlim_cur = maxsmap;
300 if (limp->rlim_max > maxsmap)
301 limp->rlim_max = maxsmap;
302
303 /*
304 * Return EINVAL if the new stack size limit is lower than
305 * current usage. Otherwise, the process would get SIGSEGV the
306 * moment it would try to access anything on it's current stack.
307 * This conforms to SUSv2.
308 */
309 if (limp->rlim_cur < p->p_vmspace->vm_ssize * PAGE_SIZE
310 || limp->rlim_max < p->p_vmspace->vm_ssize * PAGE_SIZE)
311 return (EINVAL);
312
313 /*
314 * Stack is allocated to the max at exec time with
315 * only "rlim_cur" bytes accessible (In other words,
316 * allocates stack dividing two contiguous regions at
317 * "rlim_cur" bytes boundary).
318 *
319 * Since allocation is done in terms of page, roundup
320 * "rlim_cur" (otherwise, contiguous regions
321 * overlap). If stack limit is going up make more
322 * accessible, if going down make inaccessible.
323 */
324 limp->rlim_cur = round_page(limp->rlim_cur);
325 if (limp->rlim_cur != alimp->rlim_cur) {
326 vaddr_t addr;
327 vsize_t size;
328 vm_prot_t prot;
329
330 if (limp->rlim_cur > alimp->rlim_cur) {
331 prot = VM_PROT_ALL;
332 size = limp->rlim_cur - alimp->rlim_cur;
333 addr = USRSTACK - limp->rlim_cur;
334 } else {
335 prot = VM_PROT_NONE;
336 size = alimp->rlim_cur - limp->rlim_cur;
337 addr = USRSTACK - alimp->rlim_cur;
338 }
339 (void) uvm_map_protect(&p->p_vmspace->vm_map,
340 addr, addr+size, prot, FALSE);
341 }
342 break;
343
344 case RLIMIT_NOFILE:
345 if (limp->rlim_cur > maxfiles)
346 limp->rlim_cur = maxfiles;
347 if (limp->rlim_max > maxfiles)
348 limp->rlim_max = maxfiles;
349 break;
350
351 case RLIMIT_NPROC:
352 if (limp->rlim_cur > maxproc)
353 limp->rlim_cur = maxproc;
354 if (limp->rlim_max > maxproc)
355 limp->rlim_max = maxproc;
356 break;
357 }
358 *alimp = *limp;
359 return (0);
360 }
361
362 /* ARGSUSED */
363 int
364 sys_getrlimit(l, v, retval)
365 struct lwp *l;
366 void *v;
367 register_t *retval;
368 {
369 struct sys_getrlimit_args /* {
370 syscallarg(int) which;
371 syscallarg(struct rlimit *) rlp;
372 } */ *uap = v;
373 struct proc *p = l->l_proc;
374 int which = SCARG(uap, which);
375
376 if ((u_int)which >= RLIM_NLIMITS)
377 return (EINVAL);
378 return (copyout(&p->p_rlimit[which], SCARG(uap, rlp),
379 sizeof(struct rlimit)));
380 }
381
382 /*
383 * Transform the running time and tick information in proc p into user,
384 * system, and interrupt time usage.
385 */
386 void
387 calcru(p, up, sp, ip)
388 struct proc *p;
389 struct timeval *up;
390 struct timeval *sp;
391 struct timeval *ip;
392 {
393 u_quad_t u, st, ut, it, tot;
394 long sec, usec;
395 int s;
396 struct timeval tv;
397 struct lwp *l;
398
399 s = splstatclock();
400 st = p->p_sticks;
401 ut = p->p_uticks;
402 it = p->p_iticks;
403 splx(s);
404
405 tot = st + ut + it;
406 if (tot == 0) {
407 up->tv_sec = up->tv_usec = 0;
408 sp->tv_sec = sp->tv_usec = 0;
409 if (ip != NULL)
410 ip->tv_sec = ip->tv_usec = 0;
411 return;
412 }
413
414 sec = p->p_rtime.tv_sec;
415 usec = p->p_rtime.tv_usec;
416 for (l = LIST_FIRST(&p->p_lwps); l != NULL;
417 l = LIST_NEXT(l, l_sibling)) {
418 if (l->l_stat == LSONPROC) {
419 struct schedstate_percpu *spc;
420
421 KDASSERT(l->l_cpu != NULL);
422 spc = &l->l_cpu->ci_schedstate;
423
424 /*
425 * Adjust for the current time slice. This is
426 * actually fairly important since the error
427 * here is on the order of a time quantum,
428 * which is much greater than the sampling
429 * error.
430 */
431 microtime(&tv);
432 sec += tv.tv_sec - spc->spc_runtime.tv_sec;
433 usec += tv.tv_usec - spc->spc_runtime.tv_usec;
434
435 break;
436 }
437 }
438 u = (u_quad_t) sec * 1000000 + usec;
439 st = (u * st) / tot;
440 sp->tv_sec = st / 1000000;
441 sp->tv_usec = st % 1000000;
442 ut = (u * ut) / tot;
443 up->tv_sec = ut / 1000000;
444 up->tv_usec = ut % 1000000;
445 if (ip != NULL) {
446 it = (u * it) / tot;
447 ip->tv_sec = it / 1000000;
448 ip->tv_usec = it % 1000000;
449 }
450 }
451
452 /* ARGSUSED */
453 int
454 sys_getrusage(l, v, retval)
455 struct lwp *l;
456 void *v;
457 register_t *retval;
458 {
459 struct sys_getrusage_args /* {
460 syscallarg(int) who;
461 syscallarg(struct rusage *) rusage;
462 } */ *uap = v;
463 struct rusage *rup;
464 struct proc *p = l->l_proc;
465
466 switch (SCARG(uap, who)) {
467
468 case RUSAGE_SELF:
469 rup = &p->p_stats->p_ru;
470 calcru(p, &rup->ru_utime, &rup->ru_stime, NULL);
471 break;
472
473 case RUSAGE_CHILDREN:
474 rup = &p->p_stats->p_cru;
475 break;
476
477 default:
478 return (EINVAL);
479 }
480 return (copyout(rup, SCARG(uap, rusage), sizeof(struct rusage)));
481 }
482
483 void
484 ruadd(ru, ru2)
485 struct rusage *ru, *ru2;
486 {
487 long *ip, *ip2;
488 int i;
489
490 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
491 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
492 if (ru->ru_maxrss < ru2->ru_maxrss)
493 ru->ru_maxrss = ru2->ru_maxrss;
494 ip = &ru->ru_first; ip2 = &ru2->ru_first;
495 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
496 *ip++ += *ip2++;
497 }
498
499 /*
500 * Make a copy of the plimit structure.
501 * We share these structures copy-on-write after fork,
502 * and copy when a limit is changed.
503 */
504 struct plimit *
505 limcopy(lim)
506 struct plimit *lim;
507 {
508 struct plimit *newlim;
509
510 newlim = pool_get(&plimit_pool, PR_WAITOK);
511 memcpy(newlim->pl_rlimit, lim->pl_rlimit,
512 sizeof(struct rlimit) * RLIM_NLIMITS);
513 if (lim->pl_corename == defcorename) {
514 newlim->pl_corename = defcorename;
515 } else {
516 newlim->pl_corename = malloc(strlen(lim->pl_corename)+1,
517 M_TEMP, M_WAITOK);
518 strcpy(newlim->pl_corename, lim->pl_corename);
519 }
520 newlim->p_lflags = 0;
521 newlim->p_refcnt = 1;
522 return (newlim);
523 }
524
525 void
526 limfree(lim)
527 struct plimit *lim;
528 {
529
530 if (--lim->p_refcnt > 0)
531 return;
532 #ifdef DIAGNOSTIC
533 if (lim->p_refcnt < 0)
534 panic("limfree");
535 #endif
536 if (lim->pl_corename != defcorename)
537 free(lim->pl_corename, M_TEMP);
538 pool_put(&plimit_pool, lim);
539 }
540
541 struct pstats *
542 pstatscopy(ps)
543 struct pstats *ps;
544 {
545
546 struct pstats *newps;
547
548 newps = pool_get(&pstats_pool, PR_WAITOK);
549
550 memset(&newps->pstat_startzero, 0,
551 (unsigned) ((caddr_t)&newps->pstat_endzero -
552 (caddr_t)&newps->pstat_startzero));
553 memcpy(&newps->pstat_startcopy, &ps->pstat_startcopy,
554 ((caddr_t)&newps->pstat_endcopy -
555 (caddr_t)&newps->pstat_startcopy));
556
557 return (newps);
558
559 }
560
561 void
562 pstatsfree(ps)
563 struct pstats *ps;
564 {
565
566 pool_put(&pstats_pool, ps);
567 }
568