diff options
author | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
---|---|---|
committer | stevel@tonic-gate <none@none> | 2005-06-14 00:00:00 -0700 |
commit | 7c478bd95313f5f23a4c958a745db2134aa03244 (patch) | |
tree | c871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/uts/common/syscall/tasksys.c | |
download | illumos-gate-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz |
OpenSolaris Launch
Diffstat (limited to 'usr/src/uts/common/syscall/tasksys.c')
-rw-r--r-- | usr/src/uts/common/syscall/tasksys.c | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/usr/src/uts/common/syscall/tasksys.c b/usr/src/uts/common/syscall/tasksys.c new file mode 100644 index 0000000000..10b7e95c76 --- /dev/null +++ b/usr/src/uts/common/syscall/tasksys.c @@ -0,0 +1,266 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * System calls for creating and inquiring about tasks and projects + */ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/thread.h> +#include <sys/proc.h> +#include <sys/task.h> +#include <sys/systm.h> +#include <sys/project.h> +#include <sys/cpuvar.h> +#include <sys/policy.h> +#include <sys/zone.h> + +/* + * Limit projlist to 256k projects. + */ +#define MAX_PROJLIST_BUFSIZE 1048576 + +typedef struct projlist_walk { + projid_t *pw_buf; + size_t pw_bufsz; +} projlist_walk_t; + + +/* + * taskid_t tasksys_settaskid(projid_t projid, uint_t flags); + * + * Overview + * Place the calling process in a new task if sufficiently privileged. If the + * present task is finalized, the process may not create a new task. + * + * Return values + * 0 on success, errno on failure. + */ +static long +tasksys_settaskid(projid_t projid, uint_t flags) +{ + proc_t *p = ttoproc(curthread); + kproject_t *oldpj; + kproject_t *kpj; + task_t *tk, *oldtk; + rctl_entity_p_t e; + zone_t *zone; + int rctlfail = 0; + + if (secpolicy_tasksys(CRED()) != 0) + return (set_errno(EPERM)); + + if (projid < 0 || projid > MAXPROJID) + return (set_errno(EINVAL)); + + if (flags & ~TASK_FINAL) + return (set_errno(EINVAL)); + + mutex_enter(&pidlock); + if (p->p_task->tk_flags & TASK_FINAL) { + mutex_exit(&pidlock); + return (set_errno(EACCES)); + } + mutex_exit(&pidlock); + + /* + * Try to stop all other lwps in the process while we're changing + * our project. This way, curthread doesn't need to grab its own + * thread_lock to find its project ID (see curprojid()). If this + * is the /proc agent lwp, we know that the other lwps are already + * held. If we failed to hold all lwps, bail out and return EINTR. + */ + if (curthread != p->p_agenttp && !holdlwps(SHOLDFORK1)) + return (set_errno(EINTR)); + /* + * Put a hold on our new project and make sure that nobody is + * trying to bind it to a pool while we're joining. + */ + kpj = project_hold_by_id(projid, getzoneid(), PROJECT_HOLD_INSERT); + e.rcep_p.proj = kpj; + e.rcep_t = RCENTITY_PROJECT; + + mutex_enter(&p->p_lock); + oldpj = p->p_task->tk_proj; + zone = p->p_zone; + + mutex_enter(&zone->zone_nlwps_lock); + + if (kpj->kpj_nlwps + p->p_lwpcnt > kpj->kpj_nlwps_ctl) + if (rctl_test_entity(rc_project_nlwps, kpj->kpj_rctls, p, &e, + p->p_lwpcnt, 0) & RCT_DENY) + rctlfail = 1; + + if (kpj->kpj_ntasks + 1 > kpj->kpj_ntasks_ctl) + if (rctl_test_entity(rc_project_ntasks, kpj->kpj_rctls, p, &e, + 1, 0) & RCT_DENY) + rctlfail = 1; + + if (rctlfail) { + mutex_exit(&zone->zone_nlwps_lock); + if (curthread != p->p_agenttp) + continuelwps(p); + mutex_exit(&p->p_lock); + return (set_errno(EAGAIN)); + } + kpj->kpj_nlwps += p->p_lwpcnt; + kpj->kpj_ntasks++; + + oldpj->kpj_nlwps -= p->p_lwpcnt; + + mutex_exit(&zone->zone_nlwps_lock); + mutex_exit(&p->p_lock); + + mutex_enter(&kpj->kpj_poolbind); + tk = task_create(projid, curproc->p_zone); + mutex_enter(&cpu_lock); + /* + * Returns with p_lock held. + */ + oldtk = task_join(tk, flags); + if (curthread != p->p_agenttp) + continuelwps(p); + mutex_exit(&p->p_lock); + mutex_exit(&cpu_lock); + mutex_exit(&kpj->kpj_poolbind); + task_rele(oldtk); + project_rele(kpj); + return (tk->tk_tkid); +} + +/* + * taskid_t tasksys_gettaskid(void); + * + * Overview + * Return the current task ID for this process. + * + * Return value + * The ID for the task to which the current process belongs. + */ +static long +tasksys_gettaskid() +{ + long ret; + proc_t *p = ttoproc(curthread); + + mutex_enter(&pidlock); + ret = p->p_task->tk_tkid; + mutex_exit(&pidlock); + return (ret); +} + +/* + * projid_t tasksys_getprojid(void); + * + * Overview + * Return the current project ID for this process. + * + * Return value + * The ID for the project to which the current process belongs. + */ +static long +tasksys_getprojid() +{ + long ret; + proc_t *p = ttoproc(curthread); + + mutex_enter(&pidlock); + ret = p->p_task->tk_proj->kpj_id; + mutex_exit(&pidlock); + return (ret); +} + +static int +tasksys_projlist_cb(kproject_t *kp, void *buf) +{ + projlist_walk_t *pw = (projlist_walk_t *)buf; + + if (pw && pw->pw_bufsz >= sizeof (projid_t)) { + *pw->pw_buf = kp->kpj_id; + pw->pw_buf++; + pw->pw_bufsz -= sizeof (projid_t); + } + + return (0); +} + +/* + * long tasksys_projlist(void *buf, size_t bufsz) + * + * Overview + * Return a buffer containing the project IDs of all currently active projects + * in the current zone. + * + * Return values + * The minimum size of a buffer sufficiently large to contain all of the + * active project IDs, or -1 if an error occurs during copyout. + */ +static long +tasksys_projlist(void *buf, size_t bufsz) +{ + long ret = 0; + projlist_walk_t pw; + void *kbuf; + + if (buf == NULL || bufsz == 0) + return (project_walk_all(getzoneid(), tasksys_projlist_cb, + NULL)); + + if (bufsz > MAX_PROJLIST_BUFSIZE) + return (set_errno(ENOMEM)); + + kbuf = pw.pw_buf = kmem_zalloc(bufsz, KM_SLEEP); + pw.pw_bufsz = bufsz; + + ret = project_walk_all(getzoneid(), tasksys_projlist_cb, &pw); + + if (copyout(kbuf, buf, bufsz) == -1) + ret = set_errno(EFAULT); + + kmem_free(kbuf, bufsz); + return (ret); +} + +long +tasksys(int code, projid_t projid, uint_t flags, void *projidbuf, size_t pbufsz) +{ + switch (code) { + case 0: + return (tasksys_settaskid(projid, flags)); + case 1: + return (tasksys_gettaskid()); + case 2: + return (tasksys_getprojid()); + case 3: + return (tasksys_projlist(projidbuf, pbufsz)); + default: + return (set_errno(EINVAL)); + } +} |