pool_pset.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
* 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"
#include <sys/pool_impl.h>
#include <sys/pool_pset.h>
/*
* Processor set plugin for pools.
*
* This file contains various routines used by the common pools layer to create,
* modify, and destroy processor sets. All processor sets created by this
* plug-in are stored in the pool_pset_list doubly-linked list, which is
* guaranteed to always have an entry for the default processor set,
* pool_pset_default.
*
* Interaction with zones:
*
* If pools are enabled, non-global zones only have visibility into the
* pset of the pool to which they are bound. This is accomplished by
* changing the set of processors and processor sets which are visible
* through both systemcall interfaces and system kstats.
*
* To avoid grabbing pool_lock() during cpu change operations, we cache
* the pset the zone is currently bound to, and can read this value
* while under cpu_lock. The special psetid_t token ZONE_PS_INVAL means
* that pools are disabled, and provides a mechanism for determining if the
* status of pools without grabbing pool_lock().
*
* To avoid grabbing any locks to determine the instantaneous value of
* the number of configured and online cpus in the zone, we also cache
* these values in a zone_t. If these values are zero, the pools
* facility must be disabled, in which case relevant systemcall
* interfaces will return the values for the system as a whole.
*
* The various kstat interfaces are dealt with as follows: if pools are
* disabled all cpu-related kstats should be exported to all zones.
* When pools are enabled we begin maintaining a list of "permitted
* zones" on a per-kstat basis. There are various hooks throughout the
* code to update this list when certain pools- or cpu-related events
* occur.
*/
static pool_pset_t *
{
ASSERT(pool_lock_held());
return (pset);
}
return (NULL);
}
struct setup_arg {
};
/*
* Callback function used to apply a cpu configuration event to a zone.
*/
static int
{
if (zone == global_zone)
return (0);
return (0); /* ignore */
case CPU_CONFIG:
break;
case CPU_UNCONFIG:
break;
case CPU_ON:
break;
case CPU_OFF:
break;
case CPU_CPUPART_IN:
break;
case CPU_CPUPART_OUT:
break;
default:
}
return (0);
}
/*
* Callback function to be executed when a noteworthy cpu event takes
* place. Will ensure that the event is reflected by the zones which
* were affected by it.
*/
/* ARGSUSED */
static int
{
int error;
cpu_t *c;
if (!pool_pset_enabled())
return (0);
return (0);
return (0);
}
/*
* Initialize processor set plugin. Called once at boot time.
*/
void
pool_pset_init(void)
{
}
/*
* Dummy wrapper function that returns 0 to satisfy zone_walk().
*/
static int
{
return (0);
}
/*
* Enable processor set plugin.
*/
int
pool_pset_enable(void)
{
int error;
ASSERT(pool_lock_held());
/*
* Can't enable pools if there are existing cpu partitions.
*/
if (cp_numparts > 1) {
return (EEXIST);
}
/*
* We want to switch things such that everything that was tagged with
* the special ALL_ZONES token now is explicitly visible to all zones:
* first add individual zones to the visibility list then remove the
* special "ALL_ZONES" token. There must only be the default pset
* (PS_NONE) active if pools are being enabled, so we only need to
* deal with it.
*
* We want to make pool_pset_enabled() start returning B_TRUE before
* we call any of the visibility update functions.
*/
/*
* We need to explicitly handle the global zone since
* zone_pset_set() won't modify it.
*/
/*
* A NULL argument means the ALL_ZONES token.
*/
/*
* It is safe to drop cpu_lock here. We're still
* holding pool_lock so no new cpu partitions can
* be created while we're here.
*/
return (0);
}
/*
* Disable processor set plugin.
*/
int
pool_pset_disable(void)
{
int error;
ASSERT(pool_lock_held());
return (EBUSY);
}
/*
* Remove all non-system CPU and processor set properties
*/
continue;
}
}
/*
* We want to switch things such that everything is now visible
* to ALL_ZONES: first add the special "ALL_ZONES" token to the
* visibility list then remove individual zones. There must
* only be the default pset active if pools are being disabled,
* so we only need to deal with it.
*/
/*
* pool_pset_enabled() will henceforth return B_FALSE.
*/
}
return (0);
}
/*
* Create new processor set and give it a temporary name.
*/
int
{
char pset_name[40];
int err;
ASSERT(pool_lock_held());
return (err);
pset->pset_npools = 0;
pool_pset_mod = gethrtime();
return (0);
}
/*
* Destroy existing processor set.
*/
int
{
int ret;
ASSERT(pool_lock_held());
return (EINVAL);
return (ESRCH);
return (EBUSY);
return (ret);
pool_pset_mod = gethrtime();
return (0);
}
/*
* Change the visibility of a pset (and all contained cpus) in a zone.
* A NULL zone argument implies the special ALL_ZONES token.
*/
static void
{
cpu_t *c;
if (add)
else
}
c = cpu_list;
do {
if (add)
cpu_visibility_add(c, zone);
else
}
}
/*
* Make the processor set visible to the zone. A NULL value for
* the zone means that the special ALL_ZONES token should be added to
* the visibility list.
*/
void
{
}
/*
* Remove zone's visibility into the processor set. A NULL value for
* the zone means that the special ALL_ZONES token should be removed
* from the visibility list.
*/
void
{
}
/*
* Quick way of seeing if pools are enabled (as far as processor sets are
* concerned) without holding pool_lock().
*/
pool_pset_enabled(void)
{
}
struct assoc_zone_arg {
};
/*
* Callback function to update a zone's processor set visibility when
* a pool is associated with a processor set.
*/
static int
{
ASSERT(pool_lock_held());
if (zoneid == GLOBAL_ZONEID)
return (0);
return (0);
}
/*
* Associate pool with new processor set.
*/
int
{
int err = 0;
ASSERT(pool_lock_held());
return (ESRCH);
}
/*
* Already associated.
*/
return (0);
}
/*
* Hang the new pset off the pool, and rebind all of the pool's
* processes to it. If pool_do_bind fails, all processes will remain
* bound to the old set.
*/
if (err) {
} else {
struct assoc_zone_arg azarg;
/*
* Update zones' visibility to reflect changes.
*/
oldpset->pset_npools--;
pset->pset_npools++;
}
return (err);
}
/*
* Transfer specified CPUs between processor sets.
*/
int
{
int ret = 0;
int id;
ASSERT(pool_lock_held());
return (EINVAL);
break;
}
break;
}
if (ret == 0)
pool_pset_mod = gethrtime();
return (ret);
}
/*
* Bind process to processor set. This should never fail because
* we should've done all preliminary checks before calling it.
*/
void
{
kthread_t *t;
int ret;
ASSERT(pool_lock_held());
return;
do {
t->t_bind_pset = psetid;
}
/*
* See the comment above pool_do_bind() for the semantics of the pset_bind_*()
* functions. These must be kept in sync with cpupart_move_thread, and
* anything else that could fail a pool_pset_bind.
*
* Returns non-zero errno on failure and zero on success.
* Iff successful, cpu_lock is held on return.
*/
int
{
kthread_t *t;
int ret;
ASSERT(pool_lock_held());
return (ENOTSUP);
}
/*
* Check for the PRIV_PROC_PRIOCNTL privilege that is required
* to enter and exit scheduling classes. If other privileges
* are required by CL_ENTERCLASS/CL_CANEXIT types of routines
* in the future, this code will have to be updated.
*/
if (secpolicy_setpriority(pcred) != 0) {
return (EPERM);
}
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
continue;
}
/*
* Check our basic permissions to control this process.
*/
mutex_exit(&p->p_lock);
return (EPERM);
}
do {
/*
* Check that all threads can be moved to
* a new processor set.
*/
thread_lock(t);
thread_unlock(t);
if (ret != 0) {
mutex_exit(&p->p_lock);
return (ret);
}
mutex_exit(&p->p_lock);
}
return (0); /* with cpu_lock held and weakbinding stopped */
}
/*ARGSUSED*/
void
{
}
void
pset_bind_finish(void)
{
}
static pool_property_t pool_pset_props[] = {
{ "pset.poold.objectives", DATA_TYPE_STRING,
PP_RDWR | PP_OPTIONAL },
{ NULL, 0, 0 }
};
static pool_property_t pool_cpu_props[] = {
{ "cpu.pinned", DATA_TYPE_BYTE,
PP_RDWR | PP_OPTIONAL },
{ NULL, 0, 0 }
};
/*
* Put property on the specified processor set.
*/
int
{
int ret;
ASSERT(pool_lock_held());
return (ESRCH);
if (ret == 0)
pool_pset_mod = gethrtime();
return (ret);
}
/*
* Remove existing processor set property.
*/
int
{
int ret;
ASSERT(pool_lock_held());
return (EINVAL);
if (ret == 0)
pool_pset_mod = gethrtime();
return (ret);
}
/*
* Put new CPU property.
* Handle special case of "cpu.status".
*/
int
{
int ret = 0;
ASSERT(pool_lock_held());
char *val;
int status;
int old_status;
else
return (EINVAL);
} else {
"cpu.comment", "");
}
if (ret == 0)
pool_cpu_mod = gethrtime();
}
return (ret);
}
/*
* Remove existing CPU property.
*/
int
{
int ret;
ASSERT(pool_lock_held());
} else {
else
}
if (ret == 0)
pool_cpu_mod = gethrtime();
return (ret);
}
/*
* This macro returns load average multiplied by 1000 w/o losing precision
*/
/*
* Take a snapshot of the current state of processor sets and CPUs,
* pack it in the exacct format, and attach it to specified exacct record.
*/
int
{
char *buf;
int ncpu;
ASSERT(pool_lock_held());
continue;
/*
* Pack info for all CPUs in this processor set.
*/
ncpu = 0;
do {
continue;
ncpu++;
| EXC_LOCAL | EXD_GROUP_CPU);
sizeof (processorid_t),
"cpu.comment", "");
}
(char *)cpu_get_state_str(cpu));
bufsz = 0;
NV_ENCODE_NATIVE, 0);
(void) nvlist_free(nvl);
bufsz = 0;
(void) nvlist_free(nvl);
}
return (0);
}
/*
* Get dynamic property for processor sets.
* The only dynamic property currently implemented is "pset.load".
*/
int
{
ASSERT(pool_lock_held());
return (EINVAL);
}
else
return (ret);
}
/*
* Get dynamic property for CPUs.
* The only dynamic property currently implemented is "cpu.status".
*/
int
{
ASSERT(pool_lock_held());
return (ESRCH);
}
(char *)cpu_get_state_str(cpu));
} else {
}
return (ret);
}