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