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