4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright (c) 2013, Joyent, Inc. All rights reserved.
30 * System calls for creating and inquiring about tasks and projects
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <sys/errno.h>
36 #include <sys/thread.h>
39 #include <sys/systm.h>
40 #include <sys/project.h>
41 #include <sys/cpuvar.h>
42 #include <sys/policy.h>
47 * Limit projlist to 256k projects.
49 #define MAX_PROJLIST_BUFSIZE 1048576
51 typedef struct projlist_walk
{
57 * taskid_t tasksys_settaskid(projid_t projid, uint_t flags);
60 * Place the calling process in a new task if sufficiently privileged. If the
61 * present task is finalized, the process may not create a new task.
64 * 0 on success, errno on failure.
67 tasksys_settaskid(projid_t projid
, uint_t flags
)
69 proc_t
*p
= ttoproc(curthread
);
77 if (secpolicy_tasksys(CRED()) != 0)
78 return (set_errno(EPERM
));
80 if (projid
< 0 || projid
> MAXPROJID
)
81 return (set_errno(EINVAL
));
83 if (flags
& ~TASK_FINAL
)
84 return (set_errno(EINVAL
));
86 mutex_enter(&pidlock
);
87 if (p
->p_task
->tk_flags
& TASK_FINAL
) {
89 return (set_errno(EACCES
));
94 * Try to stop all other lwps in the process while we're changing
95 * our project. This way, curthread doesn't need to grab its own
96 * thread_lock to find its project ID (see curprojid()). If this
97 * is the /proc agent lwp, we know that the other lwps are already
98 * held. If we failed to hold all lwps, bail out and return EINTR.
100 if (curthread
!= p
->p_agenttp
&& !holdlwps(SHOLDFORK1
))
101 return (set_errno(EINTR
));
103 * Put a hold on our new project and make sure that nobody is
104 * trying to bind it to a pool while we're joining.
106 kpj
= project_hold_by_id(projid
, p
->p_zone
, PROJECT_HOLD_INSERT
);
108 e
.rcep_t
= RCENTITY_PROJECT
;
110 mutex_enter(&p
->p_lock
);
111 oldpj
= p
->p_task
->tk_proj
;
114 mutex_enter(&zone
->zone_nlwps_lock
);
115 mutex_enter(&zone
->zone_mem_lock
);
117 if (kpj
->kpj_nlwps
+ p
->p_lwpcnt
> kpj
->kpj_nlwps_ctl
)
118 if (rctl_test_entity(rc_project_nlwps
, kpj
->kpj_rctls
, p
, &e
,
119 p
->p_lwpcnt
, 0) & RCT_DENY
)
122 if (kpj
->kpj_ntasks
+ 1 > kpj
->kpj_ntasks_ctl
)
123 if (rctl_test_entity(rc_project_ntasks
, kpj
->kpj_rctls
, p
, &e
,
127 if (kpj
!= proj0p
&& kpj
->kpj_nprocs
+ 1 > kpj
->kpj_nprocs_ctl
)
128 if (rctl_test_entity(rc_project_nprocs
, kpj
->kpj_rctls
, p
, &e
,
132 if (kpj
->kpj_data
.kpd_locked_mem
+ p
->p_locked_mem
>
133 kpj
->kpj_data
.kpd_locked_mem_ctl
)
134 if (rctl_test_entity(rc_project_locked_mem
, kpj
->kpj_rctls
, p
,
135 &e
, p
->p_locked_mem
, 0) & RCT_DENY
)
138 mutex_enter(&(kpj
->kpj_data
.kpd_crypto_lock
));
139 if (kpj
->kpj_data
.kpd_crypto_mem
+ p
->p_crypto_mem
>
140 kpj
->kpj_data
.kpd_crypto_mem_ctl
)
141 if (rctl_test_entity(rc_project_crypto_mem
, kpj
->kpj_rctls
, p
,
142 &e
, p
->p_crypto_mem
, 0) & RCT_DENY
)
146 mutex_exit(&(kpj
->kpj_data
.kpd_crypto_lock
));
147 mutex_exit(&zone
->zone_mem_lock
);
148 mutex_exit(&zone
->zone_nlwps_lock
);
149 if (curthread
!= p
->p_agenttp
)
151 mutex_exit(&p
->p_lock
);
153 return (set_errno(EAGAIN
));
155 kpj
->kpj_data
.kpd_crypto_mem
+= p
->p_crypto_mem
;
156 mutex_exit(&(kpj
->kpj_data
.kpd_crypto_lock
));
157 kpj
->kpj_data
.kpd_locked_mem
+= p
->p_locked_mem
;
158 kpj
->kpj_nlwps
+= p
->p_lwpcnt
;
162 oldpj
->kpj_data
.kpd_locked_mem
-= p
->p_locked_mem
;
163 mutex_enter(&(oldpj
->kpj_data
.kpd_crypto_lock
));
164 oldpj
->kpj_data
.kpd_crypto_mem
-= p
->p_crypto_mem
;
165 mutex_exit(&(oldpj
->kpj_data
.kpd_crypto_lock
));
166 oldpj
->kpj_nlwps
-= p
->p_lwpcnt
;
169 mutex_exit(&zone
->zone_mem_lock
);
170 mutex_exit(&zone
->zone_nlwps_lock
);
171 mutex_exit(&p
->p_lock
);
173 mutex_enter(&kpj
->kpj_poolbind
);
174 tk
= task_create(projid
, curproc
->p_zone
);
175 mutex_enter(&cpu_lock
);
177 * Returns with p_lock held.
179 oldtk
= task_join(tk
, flags
);
180 if (curthread
!= p
->p_agenttp
)
182 mutex_exit(&p
->p_lock
);
183 mutex_exit(&cpu_lock
);
184 mutex_exit(&kpj
->kpj_poolbind
);
187 return (tk
->tk_tkid
);
191 * taskid_t tasksys_gettaskid(void);
194 * Return the current task ID for this process.
197 * The ID for the task to which the current process belongs.
203 proc_t
*p
= ttoproc(curthread
);
205 mutex_enter(&pidlock
);
206 ret
= p
->p_task
->tk_tkid
;
207 mutex_exit(&pidlock
);
212 * projid_t tasksys_getprojid(void);
215 * Return the current project ID for this process.
218 * The ID for the project to which the current process belongs.
224 proc_t
*p
= ttoproc(curthread
);
226 mutex_enter(&pidlock
);
227 ret
= p
->p_task
->tk_proj
->kpj_id
;
228 mutex_exit(&pidlock
);
233 tasksys_projlist_cb(kproject_t
*kp
, void *buf
)
235 projlist_walk_t
*pw
= (projlist_walk_t
*)buf
;
237 if (pw
&& pw
->pw_bufsz
>= sizeof (projid_t
)) {
238 *pw
->pw_buf
= kp
->kpj_id
;
240 pw
->pw_bufsz
-= sizeof (projid_t
);
247 * long tasksys_projlist(void *buf, size_t bufsz)
250 * Return a buffer containing the project IDs of all currently active projects
251 * in the current zone.
254 * The minimum size of a buffer sufficiently large to contain all of the
255 * active project IDs, or -1 if an error occurs during copyout.
258 tasksys_projlist(void *buf
, size_t bufsz
)
264 if (buf
== NULL
|| bufsz
== 0)
265 return (project_walk_all(getzoneid(), tasksys_projlist_cb
,
268 if (bufsz
> MAX_PROJLIST_BUFSIZE
)
269 return (set_errno(ENOMEM
));
271 kbuf
= pw
.pw_buf
= kmem_zalloc(bufsz
, KM_SLEEP
);
274 ret
= project_walk_all(getzoneid(), tasksys_projlist_cb
, &pw
);
276 if (copyout(kbuf
, buf
, bufsz
) == -1)
277 ret
= set_errno(EFAULT
);
279 kmem_free(kbuf
, bufsz
);
284 tasksys(int code
, projid_t projid
, uint_t flags
, void *projidbuf
, size_t pbufsz
)
288 return (tasksys_settaskid(projid
, flags
));
290 return (tasksys_gettaskid());
292 return (tasksys_getprojid());
294 return (tasksys_projlist(projidbuf
, pbufsz
));
296 return (set_errno(EINVAL
));