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