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