]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_resource.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / bsd / kern / kern_resource.c
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 2000-2008 Apple Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */
29/*-
30 * Copyright (c) 1982, 1986, 1991, 1993
31 * The Regents of the University of California. All rights reserved.
32 * (c) UNIX System Laboratories, Inc.
33 * All or some portions of this file are derived from material licensed
34 * to the University of California by American Telephone and Telegraph
35 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36 * the permission of UNIX System Laboratories, Inc.
37 *
38 * Redistribution and use in source and binary forms, with or without
39 * modification, are permitted provided that the following conditions
40 * are met:
41 * 1. Redistributions of source code must retain the above copyright
42 * notice, this list of conditions and the following disclaimer.
43 * 2. Redistributions in binary form must reproduce the above copyright
44 * notice, this list of conditions and the following disclaimer in the
45 * documentation and/or other materials provided with the distribution.
46 * 3. All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Berkeley and its contributors.
50 * 4. Neither the name of the University nor the names of its contributors
51 * may be used to endorse or promote products derived from this software
52 * without specific prior written permission.
53 *
54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 * SUCH DAMAGE.
65 *
66 * @(#)kern_resource.c 8.5 (Berkeley) 1/21/94
67 */
2d21ac55
A
68/*
69 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
70 * support for mandatory and extensible security protections. This notice
71 * is included in support of clause 2.2 (b) of the Apple Public License,
72 * Version 2.0.
73 */
1c79356b
A
74
75#include <sys/param.h>
76#include <sys/systm.h>
55e303ae 77#include <sys/sysctl.h>
1c79356b 78#include <sys/kernel.h>
91447636 79#include <sys/file_internal.h>
1c79356b
A
80#include <sys/resourcevar.h>
81#include <sys/malloc.h>
91447636
A
82#include <sys/proc_internal.h>
83#include <sys/kauth.h>
84#include <machine/spl.h>
85
86#include <sys/mount_internal.h>
87#include <sys/sysproto.h>
1c79356b 88
b0d623f7 89#include <security/audit/audit.h>
e5568f75 90
1c79356b
A
91#include <machine/vmparam.h>
92
93#include <mach/mach_types.h>
94#include <mach/time_value.h>
2d21ac55 95#include <mach/task.h>
1c79356b 96#include <mach/task_info.h>
91447636 97#include <mach/vm_map.h>
2d21ac55
A
98#include <mach/mach_vm.h>
99#include <mach/thread_act.h> /* for thread_policy_set( ) */
100#include <kern/lock.h>
101#include <kern/thread.h>
102
103#include <kern/task.h>
104#include <kern/clock.h> /* for absolutetime_to_microtime() */
d1ecb069 105#include <netinet/in.h> /* for TRAFFIC_MGT_SO_* */
2d21ac55 106#include <sys/socketvar.h> /* for struct socket */
1c79356b
A
107
108#include <vm/vm_map.h>
109
91447636
A
110int donice(struct proc *curp, struct proc *chgp, int n);
111int dosetrlimit(struct proc *p, u_int which, struct rlimit *limp);
d1ecb069
A
112int uthread_get_background_state(uthread_t);
113static void do_background_socket(struct proc *p, thread_t thread, int priority);
2d21ac55 114static int do_background_thread(struct proc *curp, int priority);
b7266188 115static int do_background_task(struct proc *curp, int priority);
1c79356b
A
116
117rlim_t maxdmap = MAXDSIZ; /* XXX */
2d21ac55 118rlim_t maxsmap = MAXSSIZ - PAGE_SIZE; /* XXX */
1c79356b 119
55e303ae
A
120/*
121 * Limits on the number of open files per process, and the number
122 * of child processes per process.
123 *
124 * Note: would be in kern/subr_param.c in FreeBSD.
125 */
b0d623f7 126__private_extern__ int maxfilesperproc = OPEN_MAX; /* per-proc open files limit */
55e303ae
A
127
128SYSCTL_INT( _kern, KERN_MAXPROCPERUID, maxprocperuid, CTLFLAG_RW,
129 &maxprocperuid, 0, "Maximum processes allowed per userid" );
130
131SYSCTL_INT( _kern, KERN_MAXFILESPERPROC, maxfilesperproc, CTLFLAG_RW,
132 &maxfilesperproc, 0, "Maximum files allowed open per process" );
133
2d21ac55
A
134/* Args and fn for proc_iteration callback used in setpriority */
135struct puser_nice_args {
136 proc_t curp;
137 int prio;
138 id_t who;
139 int * foundp;
140 int * errorp;
141};
142static int puser_donice_callback(proc_t p, void * arg);
143
144
145/* Args and fn for proc_iteration callback used in setpriority */
146struct ppgrp_nice_args {
147 proc_t curp;
148 int prio;
149 int * foundp;
150 int * errorp;
151};
152static int ppgrp_donice_callback(proc_t p, void * arg);
55e303ae 153
1c79356b
A
154/*
155 * Resource controls and accounting.
156 */
1c79356b 157int
b0d623f7 158getpriority(struct proc *curp, struct getpriority_args *uap, int32_t *retval)
1c79356b 159{
2d21ac55
A
160 struct proc *p;
161 int low = PRIO_MAX + 1;
162 kauth_cred_t my_cred;
1c79356b 163
2d21ac55
A
164 /* would also test (uap->who < 0), but id_t is unsigned */
165 if (uap->who > 0x7fffffff)
91447636
A
166 return (EINVAL);
167
1c79356b
A
168 switch (uap->which) {
169
170 case PRIO_PROCESS:
2d21ac55 171 if (uap->who == 0) {
1c79356b 172 p = curp;
2d21ac55
A
173 low = p->p_nice;
174 } else {
175 p = proc_find(uap->who);
176 if (p == 0)
177 break;
178 low = p->p_nice;
179 proc_rele(p);
180
181 }
1c79356b
A
182 break;
183
184 case PRIO_PGRP: {
2d21ac55 185 struct pgrp *pg = PGRP_NULL;
1c79356b 186
2d21ac55
A
187 if (uap->who == 0) {
188 /* returns the pgrp to ref */
189 pg = proc_pgrp(curp);
190 } else if ((pg = pgfind(uap->who)) == PGRP_NULL) {
1c79356b 191 break;
2d21ac55
A
192 }
193 /* No need for iteration as it is a simple scan */
194 pgrp_lock(pg);
1c79356b
A
195 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
196 if (p->p_nice < low)
197 low = p->p_nice;
198 }
2d21ac55
A
199 pgrp_unlock(pg);
200 pg_rele(pg);
1c79356b
A
201 break;
202 }
203
204 case PRIO_USER:
205 if (uap->who == 0)
91447636 206 uap->who = kauth_cred_getuid(kauth_cred_get());
2d21ac55
A
207
208 proc_list_lock();
209
210 for (p = allproc.lh_first; p != 0; p = p->p_list.le_next) {
211 my_cred = kauth_cred_proc_ref(p);
212 if (kauth_cred_getuid(my_cred) == uap->who &&
1c79356b
A
213 p->p_nice < low)
214 low = p->p_nice;
2d21ac55
A
215 kauth_cred_unref(&my_cred);
216 }
217
218 proc_list_unlock();
219
220 break;
221
222 case PRIO_DARWIN_THREAD: {
223 thread_t thread;
224 struct uthread *ut;
225
226 /* we currently only support the current thread */
227 if (uap->who != 0) {
228 return (EINVAL);
229 }
230
231 thread = current_thread();
232 ut = get_bsdthread_info(thread);
233
234 low = 0;
d1ecb069 235 if ( (ut->uu_flag & UT_BACKGROUND_TRAFFIC_MGT) != 0 ) {
2d21ac55
A
236 low = 1;
237 }
1c79356b 238 break;
2d21ac55 239 }
1c79356b
A
240
241 default:
242 return (EINVAL);
243 }
244 if (low == PRIO_MAX + 1)
245 return (ESRCH);
246 *retval = low;
247 return (0);
248}
249
2d21ac55
A
250/* call back function used for proc iteration in PRIO_USER */
251static int
252puser_donice_callback(proc_t p, void * arg)
253{
254 int error, n;
255 struct puser_nice_args * pun = (struct puser_nice_args *)arg;
256 kauth_cred_t my_cred;
257
258 my_cred = kauth_cred_proc_ref(p);
259 if (kauth_cred_getuid(my_cred) == pun->who) {
260 error = donice(pun->curp, p, pun->prio);
261 if (pun->errorp != NULL)
262 *pun->errorp = error;
263 if (pun->foundp != NULL) {
264 n = *pun->foundp;
265 *pun->foundp = n+1;
266 }
267 }
268 kauth_cred_unref(&my_cred);
269
270 return(PROC_RETURNED);
271}
272
273/* call back function used for proc iteration in PRIO_PGRP */
274static int
275ppgrp_donice_callback(proc_t p, void * arg)
276{
277 int error;
278 struct ppgrp_nice_args * pun = (struct ppgrp_nice_args *)arg;
279 int n;
280
281 error = donice(pun->curp, p, pun->prio);
282 if (pun->errorp != NULL)
283 *pun->errorp = error;
284 if (pun->foundp!= NULL) {
285 n = *pun->foundp;
286 *pun->foundp = n+1;
287 }
288
289 return(PROC_RETURNED);
290}
291
292/*
293 * Returns: 0 Success
294 * EINVAL
295 * ESRCH
296 * donice:EPERM
297 * donice:EACCES
298 */
1c79356b
A
299/* ARGSUSED */
300int
b0d623f7 301setpriority(struct proc *curp, struct setpriority_args *uap, __unused int32_t *retval)
1c79356b 302{
2d21ac55 303 struct proc *p;
1c79356b 304 int found = 0, error = 0;
2d21ac55 305 int refheld = 0;
1c79356b 306
e5568f75
A
307 AUDIT_ARG(cmd, uap->which);
308 AUDIT_ARG(owner, uap->who, 0);
b0d623f7 309 AUDIT_ARG(value32, uap->prio);
e5568f75 310
2d21ac55
A
311 /* would also test (uap->who < 0), but id_t is unsigned */
312 if (uap->who > 0x7fffffff)
91447636
A
313 return (EINVAL);
314
1c79356b
A
315 switch (uap->which) {
316
317 case PRIO_PROCESS:
318 if (uap->who == 0)
319 p = curp;
2d21ac55
A
320 else {
321 p = proc_find(uap->who);
322 if (p == 0)
323 break;
324 refheld = 1;
325 }
1c79356b
A
326 error = donice(curp, p, uap->prio);
327 found++;
2d21ac55
A
328 if (refheld != 0)
329 proc_rele(p);
1c79356b
A
330 break;
331
332 case PRIO_PGRP: {
2d21ac55
A
333 struct pgrp *pg = PGRP_NULL;
334 struct ppgrp_nice_args ppgrp;
1c79356b 335
2d21ac55
A
336 if (uap->who == 0) {
337 pg = proc_pgrp(curp);
338 } else if ((pg = pgfind(uap->who)) == PGRP_NULL)
1c79356b 339 break;
2d21ac55
A
340
341 ppgrp.curp = curp;
342 ppgrp.prio = uap->prio;
343 ppgrp.foundp = &found;
344 ppgrp.errorp = &error;
345
346 /* PGRP_DROPREF drops the reference on process group */
347 pgrp_iterate(pg, PGRP_DROPREF, ppgrp_donice_callback, (void *)&ppgrp, NULL, NULL);
348
1c79356b
A
349 break;
350 }
351
2d21ac55
A
352 case PRIO_USER: {
353 struct puser_nice_args punice;
354
1c79356b 355 if (uap->who == 0)
91447636 356 uap->who = kauth_cred_getuid(kauth_cred_get());
2d21ac55
A
357
358 punice.curp = curp;
359 punice.prio = uap->prio;
360 punice.who = uap->who;
361 punice.foundp = &found;
362 error = 0;
363 punice.errorp = &error;
364 proc_iterate(PROC_ALLPROCLIST, puser_donice_callback, (void *)&punice, NULL, NULL);
365
1c79356b 366 break;
2d21ac55
A
367 }
368
369 case PRIO_DARWIN_THREAD: {
370 /* we currently only support the current thread */
371 if (uap->who != 0) {
372 return (EINVAL);
373 }
374 error = do_background_thread(curp, uap->prio);
b7266188 375 (void) do_background_socket(curp, current_thread(), uap->prio);
2d21ac55
A
376 found++;
377 break;
378 }
1c79356b 379
b7266188
A
380 case PRIO_DARWIN_PROCESS: {
381 if (uap->who == 0)
382 p = curp;
383 else {
384 p = proc_find(uap->who);
385 if (p == 0)
386 break;
387 refheld = 1;
388 }
389
390 error = do_background_task(p, uap->prio);
391 (void) do_background_socket(p, NULL, uap->prio);
392
b7266188
A
393 found++;
394 if (refheld != 0)
395 proc_rele(p);
396 break;
397 }
398
1c79356b
A
399 default:
400 return (EINVAL);
401 }
402 if (found == 0)
403 return (ESRCH);
404 return (error);
405}
406
2d21ac55
A
407
408/*
409 * Returns: 0 Success
410 * EPERM
411 * EACCES
412 * mac_check_proc_sched:???
413 */
1c79356b 414int
2d21ac55 415donice(struct proc *curp, struct proc *chgp, int n)
1c79356b 416{
2d21ac55
A
417 int error = 0;
418 kauth_cred_t ucred;
419 kauth_cred_t my_cred;
420
421 ucred = kauth_cred_proc_ref(curp);
422 my_cred = kauth_cred_proc_ref(chgp);
1c79356b 423
91447636 424 if (suser(ucred, NULL) && ucred->cr_ruid &&
2d21ac55
A
425 kauth_cred_getuid(ucred) != kauth_cred_getuid(my_cred) &&
426 ucred->cr_ruid != kauth_cred_getuid(my_cred)) {
427 error = EPERM;
428 goto out;
429 }
1c79356b
A
430 if (n > PRIO_MAX)
431 n = PRIO_MAX;
432 if (n < PRIO_MIN)
433 n = PRIO_MIN;
2d21ac55
A
434 if (n < chgp->p_nice && suser(ucred, &curp->p_acflag)) {
435 error = EACCES;
436 goto out;
437 }
438#if CONFIG_MACF
439 error = mac_proc_check_sched(curp, chgp);
440 if (error)
441 goto out;
442#endif
443 proc_lock(chgp);
1c79356b 444 chgp->p_nice = n;
2d21ac55 445 proc_unlock(chgp);
1c79356b 446 (void)resetpriority(chgp);
2d21ac55
A
447out:
448 kauth_cred_unref(&ucred);
449 kauth_cred_unref(&my_cred);
450 return (error);
451}
452
b7266188
A
453static int
454do_background_task(struct proc *p, int priority)
455{
456 int error = 0;
457 task_category_policy_data_t info;
458
d1ecb069 459 /* set the max scheduling priority on the task */
b7266188
A
460 if (priority & PRIO_DARWIN_BG) {
461 info.role = TASK_THROTTLE_APPLICATION;
462 } else {
463 info.role = TASK_DEFAULT_APPLICATION;
464 }
465
466 error = task_policy_set(p->task,
467 TASK_CATEGORY_POLICY,
468 (task_policy_t) &info,
469 TASK_CATEGORY_POLICY_COUNT);
d1ecb069
A
470
471 if (error)
472 goto out;
473
474 proc_lock(p);
475
476 /* mark proc structure as backgrounded */
477 if (priority & PRIO_DARWIN_BG) {
478 p->p_lflag |= P_LBACKGROUND;
479 } else {
480 p->p_lflag &= ~P_LBACKGROUND;
481 }
482
483 /* set or reset the disk I/O priority */
484 p->p_iopol_disk = (priority == PRIO_DARWIN_BG ?
485 IOPOL_THROTTLE : IOPOL_DEFAULT);
486
487 proc_unlock(p);
488
489out:
b7266188
A
490 return (error);
491}
492
493static void
d1ecb069 494do_background_socket(struct proc *p, thread_t thread, int priority)
b7266188
A
495{
496 struct filedesc *fdp;
497 struct fileproc *fp;
498 int i;
499
500 if (priority & PRIO_DARWIN_BG) {
d1ecb069
A
501 /*
502 * For PRIO_DARWIN_PROCESS (thread is NULL), simply mark
503 * the sockets with the background flag. There's nothing
504 * to do here for the PRIO_DARWIN_THREAD case.
505 */
b7266188 506 if (thread == NULL) {
d1ecb069
A
507 proc_fdlock(p);
508 fdp = p->p_fd;
b7266188
A
509
510 for (i = 0; i < fdp->fd_nfiles; i++) {
511 struct socket *sockp;
512
513 fp = fdp->fd_ofiles[i];
514 if (fp == NULL || (fdp->fd_ofileflags[i] & UF_RESERVED) != 0 ||
515 fp->f_fglob->fg_type != DTYPE_SOCKET) {
516 continue;
517 }
518 sockp = (struct socket *)fp->f_fglob->fg_data;
d1ecb069 519 socket_set_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND);
b7266188
A
520 sockp->so_background_thread = NULL;
521 }
d1ecb069 522 proc_fdunlock(p);
b7266188
A
523 }
524
525 } else {
d1ecb069
A
526 u_int32_t traffic_mgt;
527 /*
528 * See comments on do_background_thread(). Deregulate network
529 * traffics only for setpriority(PRIO_DARWIN_THREAD).
530 */
531 traffic_mgt = (thread == NULL) ? 0 : TRAFFIC_MGT_SO_BG_REGULATE;
532
b7266188
A
533 /* disable networking IO throttle.
534 * NOTE - It is a known limitation of the current design that we
535 * could potentially clear TRAFFIC_MGT_SO_BACKGROUND bit for
536 * sockets created by other threads within this process.
537 */
d1ecb069
A
538 proc_fdlock(p);
539 fdp = p->p_fd;
b7266188
A
540 for ( i = 0; i < fdp->fd_nfiles; i++ ) {
541 struct socket *sockp;
542
543 fp = fdp->fd_ofiles[ i ];
544 if ( fp == NULL || (fdp->fd_ofileflags[ i ] & UF_RESERVED) != 0 ||
545 fp->f_fglob->fg_type != DTYPE_SOCKET ) {
546 continue;
547 }
548 sockp = (struct socket *)fp->f_fglob->fg_data;
549 /* skip if only clearing this thread's sockets */
550 if ((thread) && (sockp->so_background_thread != thread)) {
551 continue;
552 }
d1ecb069 553 socket_clear_traffic_mgt_flags(sockp, TRAFFIC_MGT_SO_BACKGROUND | traffic_mgt);
b7266188
A
554 sockp->so_background_thread = NULL;
555 }
d1ecb069 556 proc_fdunlock(p);
b7266188
A
557 }
558}
559
560
2d21ac55
A
561/*
562 * do_background_thread
563 * Returns: 0 Success
564 * XXX - todo - does this need a MACF hook?
d1ecb069
A
565 *
566 * NOTE: To maintain binary compatibility with PRIO_DARWIN_THREAD with respect
567 * to network traffic management, UT_BACKGROUND_TRAFFIC_MGT is set/cleared
568 * along with UT_BACKGROUND flag, as the latter alone no longer implies
569 * any form of traffic regulation (it simply means that the thread is
570 * background.) With PRIO_DARWIN_PROCESS, any form of network traffic
571 * management must be explicitly requested via whatever means appropriate,
572 * and only TRAFFIC_MGT_SO_BACKGROUND is set via do_background_socket().
2d21ac55
A
573 */
574static int
b7266188 575do_background_thread(struct proc *curp __unused, int priority)
2d21ac55 576{
2d21ac55
A
577 thread_t thread;
578 struct uthread *ut;
579 thread_precedence_policy_data_t policy;
2d21ac55
A
580
581 thread = current_thread();
582 ut = get_bsdthread_info(thread);
583
584 if ( (priority & PRIO_DARWIN_BG) == 0 ) {
585 /* turn off backgrounding of thread */
586 if ( (ut->uu_flag & UT_BACKGROUND) == 0 ) {
587 /* already off */
588 return(0);
589 }
590
d1ecb069
A
591 /*
592 * Clear background bit in thread and disable disk IO
593 * throttle as well as network traffic management.
594 * The corresponding socket flags for sockets created by
595 * this thread will be cleared in do_background_socket().
596 */
597 ut->uu_flag &= ~(UT_BACKGROUND | UT_BACKGROUND_TRAFFIC_MGT);
2d21ac55
A
598 ut->uu_iopol_disk = IOPOL_NORMAL;
599
600 /* reset thread priority (we did not save previous value) */
601 policy.importance = 0;
602 thread_policy_set( thread, THREAD_PRECEDENCE_POLICY,
603 (thread_policy_t)&policy,
604 THREAD_PRECEDENCE_POLICY_COUNT );
2d21ac55
A
605 return(0);
606 }
607
608 /* background this thread */
609 if ( (ut->uu_flag & UT_BACKGROUND) != 0 ) {
610 /* already backgrounded */
611 return(0);
612 }
613
d1ecb069
A
614 /*
615 * Tag thread as background and throttle disk IO, as well
616 * as regulate network traffics. Future sockets created
617 * by this thread will have their corresponding socket
618 * flags set at socket create time.
619 */
620 ut->uu_flag |= (UT_BACKGROUND | UT_BACKGROUND_TRAFFIC_MGT);
2d21ac55
A
621 ut->uu_iopol_disk = IOPOL_THROTTLE;
622
623 policy.importance = INT_MIN;
624 thread_policy_set( thread, THREAD_PRECEDENCE_POLICY,
625 (thread_policy_t)&policy,
626 THREAD_PRECEDENCE_POLICY_COUNT );
d1ecb069 627
2d21ac55 628 /* throttle networking IO happens in socket( ) syscall.
d1ecb069
A
629 * If UT_{BACKGROUND,BACKGROUND_TRAFFIC_MGT} is set in the current
630 * thread then TRAFFIC_MGT_SO_{BACKGROUND,BG_REGULATE} is set.
631 * Existing sockets are taken care of by do_background_socket().
2d21ac55
A
632 */
633 return(0);
1c79356b
A
634}
635
d1ecb069
A
636/*
637 * If the thread or its proc has been put into the background
638 * with setpriority(PRIO_DARWIN_{THREAD,PROCESS}, *, PRIO_DARWIN_BG),
639 * report that status.
640 *
641 * Returns: PRIO_DARWIN_BG if background
642 * 0 if foreground
643 */
644int
645uthread_get_background_state(uthread_t uth)
646{
647 proc_t p = uth->uu_proc;
648 if (p && (p->p_lflag & P_LBACKGROUND))
649 return PRIO_DARWIN_BG;
650
651 if (uth->uu_flag & UT_BACKGROUND)
652 return PRIO_DARWIN_BG;
653
654 return 0;
655}
1c79356b 656
2d21ac55
A
657/*
658 * Returns: 0 Success
659 * copyin:EFAULT
660 * dosetrlimit:
661 */
1c79356b
A
662/* ARGSUSED */
663int
b0d623f7 664setrlimit(struct proc *p, struct setrlimit_args *uap, __unused int32_t *retval)
1c79356b
A
665{
666 struct rlimit alim;
667 int error;
668
91447636
A
669 if ((error = copyin(uap->rlp, (caddr_t)&alim,
670 sizeof (struct rlimit))))
1c79356b 671 return (error);
2d21ac55 672
1c79356b
A
673 return (dosetrlimit(p, uap->which, &alim));
674}
675
2d21ac55
A
676/*
677 * Returns: 0 Success
678 * EINVAL
679 * ENOMEM Cannot copy limit structure
680 * suser:EPERM
681 *
682 * Notes: EINVAL is returned both for invalid arguments, and in the
683 * case that the current usage (e.g. RLIMIT_STACK) is already
684 * in excess of the requested limit.
685 */
1c79356b 686int
2d21ac55 687dosetrlimit(struct proc *p, u_int which, struct rlimit *limp)
1c79356b 688{
2d21ac55 689 struct rlimit *alimp;
1c79356b 690 int error;
2d21ac55
A
691 kern_return_t kr;
692 int posix = (which & _RLIMIT_POSIX_FLAG) ? 1 : 0;
693
694 /* Mask out POSIX flag, saved above */
695 which &= ~_RLIMIT_POSIX_FLAG;
1c79356b
A
696
697 if (which >= RLIM_NLIMITS)
698 return (EINVAL);
2d21ac55 699
1c79356b 700 alimp = &p->p_rlimit[which];
2d21ac55
A
701 if (limp->rlim_cur > limp->rlim_max)
702 return EINVAL;
703
1c79356b
A
704 if (limp->rlim_cur > alimp->rlim_max ||
705 limp->rlim_max > alimp->rlim_max)
2d21ac55 706 if ((error = suser(kauth_cred_get(), &p->p_acflag))) {
1c79356b 707 return (error);
1c79356b
A
708 }
709
2d21ac55
A
710 proc_limitblock(p);
711
712 if ((error = proc_limitreplace(p)) != 0) {
713 proc_limitunblock(p);
714 return(error);
715 }
716
717 alimp = &p->p_rlimit[which];
718
1c79356b
A
719 switch (which) {
720
2d21ac55
A
721 case RLIMIT_CPU:
722 if (limp->rlim_cur == RLIM_INFINITY) {
723 task_vtimer_clear(p->task, TASK_VTIMER_RLIM);
724 timerclear(&p->p_rlim_cpu);
725 }
726 else {
727 task_absolutetime_info_data_t tinfo;
728 mach_msg_type_number_t count;
729 struct timeval ttv, tv;
b0d623f7
A
730 clock_sec_t tv_sec;
731 clock_usec_t tv_usec;
2d21ac55
A
732
733 count = TASK_ABSOLUTETIME_INFO_COUNT;
734 task_info(p->task, TASK_ABSOLUTETIME_INFO,
735 (task_info_t)&tinfo, &count);
736 absolutetime_to_microtime(tinfo.total_user + tinfo.total_system,
b0d623f7
A
737 &tv_sec, &tv_usec);
738 ttv.tv_sec = tv_sec;
739 ttv.tv_usec = tv_usec;
2d21ac55
A
740
741 tv.tv_sec = (limp->rlim_cur > __INT_MAX__ ? __INT_MAX__ : limp->rlim_cur);
742 tv.tv_usec = 0;
743 timersub(&tv, &ttv, &p->p_rlim_cpu);
744
745 timerclear(&tv);
746 if (timercmp(&p->p_rlim_cpu, &tv, >))
747 task_vtimer_set(p->task, TASK_VTIMER_RLIM);
748 else {
749 task_vtimer_clear(p->task, TASK_VTIMER_RLIM);
750
751 timerclear(&p->p_rlim_cpu);
752
753 psignal(p, SIGXCPU);
754 }
755 }
756 break;
757
1c79356b
A
758 case RLIMIT_DATA:
759 if (limp->rlim_cur > maxdmap)
760 limp->rlim_cur = maxdmap;
761 if (limp->rlim_max > maxdmap)
762 limp->rlim_max = maxdmap;
763 break;
764
765 case RLIMIT_STACK:
2d21ac55
A
766 /* Disallow illegal stack size instead of clipping */
767 if (limp->rlim_cur > maxsmap ||
768 limp->rlim_max > maxsmap) {
769 if (posix) {
770 error = EINVAL;
771 goto out;
772 }
773 else {
774 /*
775 * 4797860 - workaround poorly written installers by
776 * doing previous implementation (< 10.5) when caller
777 * is non-POSIX conforming.
778 */
779 if (limp->rlim_cur > maxsmap)
780 limp->rlim_cur = maxsmap;
781 if (limp->rlim_max > maxsmap)
782 limp->rlim_max = maxsmap;
783 }
784 }
785
1c79356b
A
786 /*
787 * Stack is allocated to the max at exec time with only
788 * "rlim_cur" bytes accessible. If stack limit is going
789 * up make more accessible, if going down make inaccessible.
790 */
2d21ac55 791 if (limp->rlim_cur > alimp->rlim_cur) {
91447636
A
792 user_addr_t addr;
793 user_size_t size;
1c79356b 794
1c79356b 795 /* grow stack */
55e303ae
A
796 size = round_page_64(limp->rlim_cur);
797 size -= round_page_64(alimp->rlim_cur);
1c79356b
A
798
799#if STACK_GROWTH_UP
800 /* go to top of current stack */
2d21ac55
A
801 addr = p->user_stack + round_page_64(alimp->rlim_cur);
802#else /* STACK_GROWTH_UP */
803 addr = p->user_stack - round_page_64(limp->rlim_cur);
1c79356b 804#endif /* STACK_GROWTH_UP */
2d21ac55
A
805 kr = mach_vm_protect(current_map(),
806 addr, size,
807 FALSE, VM_PROT_DEFAULT);
808 if (kr != KERN_SUCCESS) {
809 error = EINVAL;
810 goto out;
811 }
812 } else if (limp->rlim_cur < alimp->rlim_cur) {
813 user_addr_t addr;
814 user_size_t size;
815 user_addr_t cur_sp;
816
1c79356b 817 /* shrink stack */
2d21ac55
A
818
819 /*
820 * First check if new stack limit would agree
821 * with current stack usage.
822 * Get the current thread's stack pointer...
823 */
824 cur_sp = thread_adjuserstack(current_thread(),
825 0);
826#if STACK_GROWTH_UP
827 if (cur_sp >= p->user_stack &&
828 cur_sp < (p->user_stack +
829 round_page_64(alimp->rlim_cur))) {
830 /* current stack pointer is in main stack */
831 if (cur_sp >= (p->user_stack +
832 round_page_64(limp->rlim_cur))) {
833 /*
834 * New limit would cause
835 * current usage to be invalid:
836 * reject new limit.
837 */
838 error = EINVAL;
839 goto out;
1c79356b 840 }
2d21ac55
A
841 } else {
842 /* not on the main stack: reject */
843 error = EINVAL;
844 goto out;
845 }
846
847#else /* STACK_GROWTH_UP */
848 if (cur_sp <= p->user_stack &&
849 cur_sp > (p->user_stack -
850 round_page_64(alimp->rlim_cur))) {
851 /* stack pointer is in main stack */
852 if (cur_sp <= (p->user_stack -
853 round_page_64(limp->rlim_cur))) {
854 /*
855 * New limit would cause
856 * current usage to be invalid:
857 * reject new limit.
858 */
859 error = EINVAL;
860 goto out;
861 }
862 } else {
863 /* not on the main stack: reject */
864 error = EINVAL;
865 goto out;
866 }
867#endif /* STACK_GROWTH_UP */
868
869 size = round_page_64(alimp->rlim_cur);
870 size -= round_page_64(limp->rlim_cur);
871
872#if STACK_GROWTH_UP
873 addr = p->user_stack + round_page_64(limp->rlim_cur);
874#else /* STACK_GROWTH_UP */
875 addr = p->user_stack - round_page_64(alimp->rlim_cur);
876#endif /* STACK_GROWTH_UP */
877
878 kr = mach_vm_protect(current_map(),
879 addr, size,
880 FALSE, VM_PROT_NONE);
881 if (kr != KERN_SUCCESS) {
882 error = EINVAL;
883 goto out;
884 }
885 } else {
886 /* no change ... */
1c79356b
A
887 }
888 break;
889
890 case RLIMIT_NOFILE:
55e303ae 891 /*
2d21ac55
A
892 * Only root can set the maxfiles limits, as it is
893 * systemwide resource. If we are expecting POSIX behavior,
894 * instead of clamping the value, return EINVAL. We do this
895 * because historically, people have been able to attempt to
896 * set RLIM_INFINITY to get "whatever the maximum is".
55e303ae
A
897 */
898 if ( is_suser() ) {
2d21ac55
A
899 if (limp->rlim_cur != alimp->rlim_cur &&
900 limp->rlim_cur > (rlim_t)maxfiles) {
901 if (posix) {
902 error = EINVAL;
903 goto out;
904 }
1c79356b 905 limp->rlim_cur = maxfiles;
2d21ac55
A
906 }
907 if (limp->rlim_max != alimp->rlim_max &&
908 limp->rlim_max > (rlim_t)maxfiles)
1c79356b 909 limp->rlim_max = maxfiles;
55e303ae
A
910 }
911 else {
2d21ac55
A
912 if (limp->rlim_cur != alimp->rlim_cur &&
913 limp->rlim_cur > (rlim_t)maxfilesperproc) {
914 if (posix) {
915 error = EINVAL;
916 goto out;
917 }
55e303ae 918 limp->rlim_cur = maxfilesperproc;
2d21ac55
A
919 }
920 if (limp->rlim_max != alimp->rlim_max &&
921 limp->rlim_max > (rlim_t)maxfilesperproc)
55e303ae 922 limp->rlim_max = maxfilesperproc;
1c79356b
A
923 }
924 break;
925
926 case RLIMIT_NPROC:
55e303ae
A
927 /*
928 * Only root can set to the maxproc limits, as it is
929 * systemwide resource; all others are limited to
930 * maxprocperuid (presumably less than maxproc).
931 */
932 if ( is_suser() ) {
2d21ac55 933 if (limp->rlim_cur > (rlim_t)maxproc)
1c79356b 934 limp->rlim_cur = maxproc;
2d21ac55 935 if (limp->rlim_max > (rlim_t)maxproc)
1c79356b 936 limp->rlim_max = maxproc;
55e303ae
A
937 }
938 else {
2d21ac55 939 if (limp->rlim_cur > (rlim_t)maxprocperuid)
55e303ae 940 limp->rlim_cur = maxprocperuid;
2d21ac55 941 if (limp->rlim_max > (rlim_t)maxprocperuid)
55e303ae 942 limp->rlim_max = maxprocperuid;
1c79356b
A
943 }
944 break;
2d21ac55
A
945
946 case RLIMIT_MEMLOCK:
947 /*
948 * Tell the Mach VM layer about the new limit value.
949 */
950
951 vm_map_set_user_wire_limit(current_map(), limp->rlim_cur);
952 break;
55e303ae
A
953
954 } /* switch... */
2d21ac55 955 proc_lock(p);
1c79356b 956 *alimp = *limp;
2d21ac55
A
957 proc_unlock(p);
958 error = 0;
959out:
960 proc_limitunblock(p);
961 return (error);
1c79356b
A
962}
963
1c79356b
A
964/* ARGSUSED */
965int
b0d623f7 966getrlimit(struct proc *p, struct getrlimit_args *uap, __unused int32_t *retval)
1c79356b 967{
2d21ac55
A
968 struct rlimit lim;
969
970 /*
971 * Take out flag now in case we need to use it to trigger variant
972 * behaviour later.
973 */
974 uap->which &= ~_RLIMIT_POSIX_FLAG;
975
1c79356b
A
976 if (uap->which >= RLIM_NLIMITS)
977 return (EINVAL);
2d21ac55
A
978 proc_limitget(p, uap->which, &lim);
979 return (copyout((caddr_t)&lim,
91447636 980 uap->rlp, sizeof (struct rlimit)));
1c79356b
A
981}
982
983/*
984 * Transform the running time and tick information in proc p into user,
985 * system, and interrupt time usage.
986 */
2d21ac55 987/* No lock on proc is held for this.. */
1c79356b 988void
2d21ac55 989calcru(struct proc *p, struct timeval *up, struct timeval *sp, struct timeval *ip)
1c79356b
A
990{
991 task_t task;
992
993 timerclear(up);
994 timerclear(sp);
995 if (ip != NULL)
996 timerclear(ip);
997
998 task = p->task;
999 if (task) {
b0d623f7 1000 task_basic_info_32_data_t tinfo;
1c79356b 1001 task_thread_times_info_data_t ttimesinfo;
b0d623f7
A
1002 task_events_info_data_t teventsinfo;
1003 mach_msg_type_number_t task_info_count, task_ttimes_count;
1004 mach_msg_type_number_t task_events_count;
1c79356b
A
1005 struct timeval ut,st;
1006
b0d623f7
A
1007 task_info_count = TASK_BASIC_INFO_32_COUNT;
1008 task_info(task, TASK_BASIC2_INFO_32,
1009 (task_info_t)&tinfo, &task_info_count);
1c79356b
A
1010 ut.tv_sec = tinfo.user_time.seconds;
1011 ut.tv_usec = tinfo.user_time.microseconds;
1012 st.tv_sec = tinfo.system_time.seconds;
1013 st.tv_usec = tinfo.system_time.microseconds;
55e303ae
A
1014 timeradd(&ut, up, up);
1015 timeradd(&st, sp, sp);
1c79356b 1016
b0d623f7 1017 task_ttimes_count = TASK_THREAD_TIMES_INFO_COUNT;
1c79356b 1018 task_info(task, TASK_THREAD_TIMES_INFO,
b0d623f7 1019 (task_info_t)&ttimesinfo, &task_ttimes_count);
1c79356b
A
1020
1021 ut.tv_sec = ttimesinfo.user_time.seconds;
1022 ut.tv_usec = ttimesinfo.user_time.microseconds;
1023 st.tv_sec = ttimesinfo.system_time.seconds;
1024 st.tv_usec = ttimesinfo.system_time.microseconds;
55e303ae
A
1025 timeradd(&ut, up, up);
1026 timeradd(&st, sp, sp);
b0d623f7
A
1027
1028 task_events_count = TASK_EVENTS_INFO_COUNT;
1029 task_info(task, TASK_EVENTS_INFO,
1030 (task_info_t)&teventsinfo, &task_events_count);
1031
1032 /*
1033 * No need to lock "p": this does not need to be
1034 * completely consistent, right ?
1035 */
1036 p->p_stats->p_ru.ru_minflt = (teventsinfo.faults -
1037 teventsinfo.pageins);
1038 p->p_stats->p_ru.ru_majflt = teventsinfo.pageins;
1039 p->p_stats->p_ru.ru_nivcsw = (teventsinfo.csw -
1040 p->p_stats->p_ru.ru_nvcsw);
1041 if (p->p_stats->p_ru.ru_nivcsw < 0)
1042 p->p_stats->p_ru.ru_nivcsw = 0;
1043
1044 p->p_stats->p_ru.ru_maxrss = tinfo.resident_size;
1c79356b
A
1045 }
1046}
1047
b0d623f7
A
1048__private_extern__ void munge_user64_rusage(struct rusage *a_rusage_p, struct user64_rusage *a_user_rusage_p);
1049__private_extern__ void munge_user32_rusage(struct rusage *a_rusage_p, struct user32_rusage *a_user_rusage_p);
91447636 1050
1c79356b
A
1051/* ARGSUSED */
1052int
b0d623f7 1053getrusage(struct proc *p, struct getrusage_args *uap, __unused int32_t *retval)
1c79356b
A
1054{
1055 struct rusage *rup, rubuf;
b0d623f7
A
1056 struct user64_rusage rubuf64;
1057 struct user32_rusage rubuf32;
91447636
A
1058 size_t retsize = sizeof(rubuf); /* default: 32 bits */
1059 caddr_t retbuf = (caddr_t)&rubuf; /* default: 32 bits */
2d21ac55
A
1060 struct timeval utime;
1061 struct timeval stime;
1062
1c79356b
A
1063
1064 switch (uap->who) {
1c79356b 1065 case RUSAGE_SELF:
2d21ac55 1066 calcru(p, &utime, &stime, NULL);
2d21ac55
A
1067 proc_lock(p);
1068 rup = &p->p_stats->p_ru;
1069 rup->ru_utime = utime;
1070 rup->ru_stime = stime;
1071
1c79356b 1072 rubuf = *rup;
2d21ac55
A
1073 proc_unlock(p);
1074
1c79356b
A
1075 break;
1076
1077 case RUSAGE_CHILDREN:
2d21ac55 1078 proc_lock(p);
1c79356b
A
1079 rup = &p->p_stats->p_cru;
1080 rubuf = *rup;
2d21ac55 1081 proc_unlock(p);
1c79356b
A
1082 break;
1083
1084 default:
1085 return (EINVAL);
1086 }
91447636
A
1087 if (IS_64BIT_PROCESS(p)) {
1088 retsize = sizeof(rubuf64);
1089 retbuf = (caddr_t)&rubuf64;
b0d623f7
A
1090 munge_user64_rusage(&rubuf, &rubuf64);
1091 } else {
1092 retsize = sizeof(rubuf32);
1093 retbuf = (caddr_t)&rubuf32;
1094 munge_user32_rusage(&rubuf, &rubuf32);
91447636 1095 }
b0d623f7 1096
91447636 1097 return (copyout(retbuf, uap->rusage, retsize));
1c79356b
A
1098}
1099
1100void
2d21ac55 1101ruadd(struct rusage *ru, struct rusage *ru2)
1c79356b 1102{
2d21ac55 1103 long *ip, *ip2;
b0d623f7 1104 long i;
1c79356b
A
1105
1106 timeradd(&ru->ru_utime, &ru2->ru_utime, &ru->ru_utime);
1107 timeradd(&ru->ru_stime, &ru2->ru_stime, &ru->ru_stime);
1108 if (ru->ru_maxrss < ru2->ru_maxrss)
1109 ru->ru_maxrss = ru2->ru_maxrss;
1110 ip = &ru->ru_first; ip2 = &ru2->ru_first;
1111 for (i = &ru->ru_last - &ru->ru_first; i >= 0; i--)
1112 *ip++ += *ip2++;
1113}
1114
2d21ac55
A
1115void
1116proc_limitget(proc_t p, int which, struct rlimit * limp)
1117{
1118 proc_list_lock();
1119 limp->rlim_cur = p->p_rlimit[which].rlim_cur;
1120 limp->rlim_max = p->p_rlimit[which].rlim_max;
1121 proc_list_unlock();
1122}
1123
1124
1125void
1126proc_limitdrop(proc_t p, int exiting)
1c79356b 1127{
2d21ac55
A
1128 struct plimit * freelim = NULL;
1129 struct plimit * freeoldlim = NULL;
1130
1131 proc_list_lock();
1132
1133 if (--p->p_limit->pl_refcnt == 0) {
1134 freelim = p->p_limit;
1135 p->p_limit = NULL;
1136 }
1137 if ((exiting != 0) && (p->p_olimit != NULL) && (--p->p_olimit->pl_refcnt == 0)) {
1138 freeoldlim = p->p_olimit;
1139 p->p_olimit = NULL;
1140 }
1141
1142 proc_list_unlock();
1143 if (freelim != NULL)
1144 FREE_ZONE(freelim, sizeof *p->p_limit, M_PLIMIT);
1145 if (freeoldlim != NULL)
1146 FREE_ZONE(freeoldlim, sizeof *p->p_olimit, M_PLIMIT);
1147}
1148
1149
1150void
1151proc_limitfork(proc_t parent, proc_t child)
1152{
1153 proc_list_lock();
1154 child->p_limit = parent->p_limit;
1155 child->p_limit->pl_refcnt++;
1156 child->p_olimit = NULL;
1157 proc_list_unlock();
1158}
1159
1160void
1161proc_limitblock(proc_t p)
1162{
1163 proc_lock(p);
1164 while (p->p_lflag & P_LLIMCHANGE) {
1165 p->p_lflag |= P_LLIMWAIT;
1166 msleep(&p->p_olimit, &p->p_mlock, 0, "proc_limitblock", NULL);
1167 }
1168 p->p_lflag |= P_LLIMCHANGE;
1169 proc_unlock(p);
1170
1171}
1172
1173
1174void
1175proc_limitunblock(proc_t p)
1176{
1177 proc_lock(p);
1178 p->p_lflag &= ~P_LLIMCHANGE;
1179 if (p->p_lflag & P_LLIMWAIT) {
1180 p->p_lflag &= ~P_LLIMWAIT;
1181 wakeup(&p->p_olimit);
1182 }
1183 proc_unlock(p);
1184}
1185
1186/* This is called behind serialization provided by proc_limitblock/unlbock */
1187int
1188proc_limitreplace(proc_t p)
1189{
1190 struct plimit *copy;
1191
1192
1193 proc_list_lock();
1194
1195 if (p->p_limit->pl_refcnt == 1) {
1196 proc_list_unlock();
1197 return(0);
1198 }
1199
1200 proc_list_unlock();
1c79356b
A
1201
1202 MALLOC_ZONE(copy, struct plimit *,
2d21ac55
A
1203 sizeof(struct plimit), M_PLIMIT, M_WAITOK);
1204 if (copy == NULL) {
1205 return(ENOMEM);
1206 }
1207
1208 proc_list_lock();
1209 bcopy(p->p_limit->pl_rlimit, copy->pl_rlimit,
1c79356b 1210 sizeof(struct rlimit) * RLIM_NLIMITS);
2d21ac55
A
1211 copy->pl_refcnt = 1;
1212 /* hang on to reference to old till process exits */
1213 p->p_olimit = p->p_limit;
1214 p->p_limit = copy;
1215 proc_list_unlock();
1216
1217 return(0);
1218}
1219
1220
1221/*
1222 * iopolicysys
1223 *
1224 * Description: System call MUX for use in manipulating I/O policy attributes of the current process or thread
1225 *
1226 * Parameters: cmd Policy command
1227 * arg Pointer to policy arguments
1228 *
1229 * Returns: 0 Success
1230 * EINVAL Invalid command or invalid policy arguments
1231 *
1232 */
1233int
b0d623f7 1234iopolicysys(__unused struct proc *p, __unused struct iopolicysys_args *uap, __unused int32_t *retval)
2d21ac55
A
1235{
1236 int error = 0;
1237 thread_t thread = THREAD_NULL;
1238 int *policy;
1239 struct uthread *ut = NULL;
1240 struct _iopol_param_t iop_param;
1241
1242 if ((error = copyin(uap->arg, &iop_param, sizeof(iop_param))) != 0)
1243 goto exit;
1244
1245 if (iop_param.iop_iotype != IOPOL_TYPE_DISK) {
1246 error = EINVAL;
1247 goto exit;
1248 }
1249
1250 switch (iop_param.iop_scope) {
1251 case IOPOL_SCOPE_PROCESS:
1252 policy = &p->p_iopol_disk;
1253 break;
1254 case IOPOL_SCOPE_THREAD:
1255 thread = current_thread();
1256 ut = get_bsdthread_info(thread);
1257 policy = &ut->uu_iopol_disk;
1258 break;
1259 default:
1260 error = EINVAL;
1261 goto exit;
1262 }
1263
1264 switch(uap->cmd) {
1265 case IOPOL_CMD_SET:
1266 switch (iop_param.iop_policy) {
1267 case IOPOL_DEFAULT:
1268 case IOPOL_NORMAL:
1269 case IOPOL_THROTTLE:
1270 case IOPOL_PASSIVE:
1271 proc_lock(p);
1272 *policy = iop_param.iop_policy;
1273 proc_unlock(p);
1274 break;
1275 default:
1276 error = EINVAL;
1277 goto exit;
1278 }
1279 break;
1280 case IOPOL_CMD_GET:
1281 switch (*policy) {
1282 case IOPOL_DEFAULT:
1283 case IOPOL_NORMAL:
1284 case IOPOL_THROTTLE:
1285 case IOPOL_PASSIVE:
1286 iop_param.iop_policy = *policy;
1287 break;
1288 default: // in-kernel
1289 // this should never happen
1290 printf("%s: unknown I/O policy %d\n", __func__, *policy);
1291 // restore to default value
1292 *policy = IOPOL_DEFAULT;
1293 iop_param.iop_policy = *policy;
1294 }
1295
1296 error = copyout((caddr_t)&iop_param, uap->arg, sizeof(iop_param));
1297 break;
1298 default:
1299 error = EINVAL; // unknown command
1300 break;
1301 }
1302
1303 exit:
1304 *retval = error;
1305 return (error);
1c79356b 1306}
b0d623f7
A
1307
1308
1309boolean_t thread_is_io_throttled(void);
1310
1311boolean_t
1312thread_is_io_throttled(void) {
1313
1314 int policy;
1315 struct uthread *ut;
1316
b0d623f7
A
1317 ut = get_bsdthread_info(current_thread());
1318
d1ecb069
A
1319 if(ut){
1320 policy = current_proc()->p_iopol_disk;
b0d623f7 1321
d1ecb069
A
1322 if (ut->uu_iopol_disk != IOPOL_DEFAULT)
1323 policy = ut->uu_iopol_disk;
b0d623f7 1324
d1ecb069
A
1325 if (policy == IOPOL_THROTTLE)
1326 return TRUE;
1327 }
b0d623f7
A
1328 return FALSE;
1329}