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