Check for out of space condition before extending ifile.
[unix-history] / usr / src / sys / kern / kern_resource.c
CommitLineData
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
22struct getpriority_args {
23 int which;
24 int who;
25};
8eea23a6
KM
26getpriority(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
79struct setpriority_args {
80 int which;
81 int who;
82 int prio;
83};
8eea23a6
KM
84/* ARGSUSED */
85setpriority(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
138donice(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
160struct setrlimit_args {
161 u_int which;
162 struct orlimit *lim;
163};
8eea23a6
KM
164/* ARGSUSED */
165setrlimit(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
182struct getrlimit_args {
183 u_int which;
184 struct orlimit *rlp;
185};
eda8fb5d
KM
186/* ARGSUSED */
187getrlimit(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
206struct __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
225dosetrlimit(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
294struct __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 */
315calcru(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
367struct getrusage_args {
368 int who;
369 struct rusage *rusage;
370};
8eea23a6
KM
371/* ARGSUSED */
372getrusage(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
397ruadd(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 */
417struct plimit *
418limcopy(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}