/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/rctl_impl.h>
#include <sys/sysmacros.h>
/*
* setrctl(2), getrctl(2), and private rctlsys(2*) system calls
*
* Resource control block (rctlblk_ptr_t, rctl_opaque_t)
* The resource control system call interfaces present the resource control
* values and flags via the resource control block abstraction, made manifest
* via an opaque data type with strict type definitions. Keeping the formal
* definitions in the rcontrol block allows us to be clever in the kernel,
* combining attributes where appropriate in the current implementation while
* preserving binary compatibility in the face of implementation changes.
*/
static void
{
if (flags & RBX_FROM_BLK) {
/*
* Firing time cannot be set.
*/
}
/*
* Because the strlog() interface supports fewer options
* than are made available via the syslog() interface to
* userland, we map the syslog level down to a smaller
* set of distinct logging behaviours.
*/
rde->rcd_strlog_flags = 0;
switch (blk->rcq_global_syslog_level) {
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT:
/*FALLTHROUGH*/
case LOG_ERR:
/*FALLTHROUGH*/
case LOG_WARNING:
break;
case LOG_NOTICE:
/*FALLTHROUGH*/
case LOG_INFO: /* informational */
case LOG_DEBUG: /* debug-level messages */
default:
break;
}
}
} else {
}
}
}
}
/*
* int rctl_invalid_value(rctl_dict_entry_t *, rctl_val_t *)
*
* Overview
* Perform basic validation of proposed new resource control value against the
* global properties set on the control. Any system call operation presented
* with an invalid resource control value should return -1 and set errno to
* EINVAL.
*
* Return values
* 0 if valid, 1 if invalid.
*
* Caller's context
* No restriction on context.
*/
int
{
return (1);
return (1);
return (1);
return (1);
return (1);
return (1);
rval->rcv_action_signal == 0)
return (1);
return (1);
return (1);
return (1);
return (1);
return (0);
}
/*
* static long rctlsys_get(char *name, rctl_opaque_t *old_rblk,
* rctl_opaque_t *new_rblk, int flags)
*
* Overview
* rctlsys_get() is the implementation of the core logic of getrctl(2), the
* public system call for fetching resource control values. Three mutually
* exclusive flag values are supported: RCTL_USAGE, RCTL_FIRST and RCTL_NEXT.
* When RCTL_USAGE is presented, the current usage for the resource control
* is returned in new_blk if the resource control provides an implementation
* of the usage operation. When RCTL_FIRST is presented, the value of
* old_rblk is ignored, and the first value in the resource control value
* sequence for the named control is transformed and placed in the user
* memory location at new_rblk. In the RCTL_NEXT case, the value of old_rblk
* is examined, and the next value in the sequence is transformed and placed
* at new_rblk.
*/
static long
int flags)
{
char *kname;
int ret;
if (flags & (~RCTLSYS_MASK))
action != RCTL_USAGE)
}
}
}
if (action != RCTL_USAGE)
if (action == RCTL_USAGE) {
}
}
if (RCTLOP_NO_USAGE(rctl)) {
}
} else if (action == RCTL_FIRST) {
}
} else {
/*
* RCTL_NEXT
*/
}
if (ret != 0) {
}
}
}
return (0);
}
/*
* static long rctlsys_set(char *name, rctl_opaque_t *old_rblk,
* rctl_opaque_t *new_rblk, int flags)
*
* Overview
* rctlsys_set() is the implementation of the core login of setrctl(2), which
* allows the establishment of resource control values. Flags may take on any
* of three exclusive values: RCTL_INSERT, RCTL_DELETE, and RCTL_REPLACE.
* RCTL_INSERT ignores old_rblk and inserts the value in the appropriate
* position in the ordered sequence of resource control values. RCTL_DELETE
* ignores old_rblk and deletes the first resource control value matching
* (value, priority) in the given resource block. If no matching value is
* found, -1 is returned and errno is set to ENOENT. Finally, in the case of
* RCTL_REPLACE, old_rblk is used to match (value, priority); the matching
* resource control value in the sequence is replaced with the contents of
* new_rblk. Again, if no match is found, -1 is returned and errno is set to
* ENOENT.
*
* rctlsys_set() causes a cursor test, which can reactivate resource controls
* that have previously fired.
*/
static long
int flags)
{
char *kname;
long ret = 0;
if (flags & (~RCTLSYS_MASK))
if (action != RCTL_INSERT &&
action != RCTL_DELETE &&
action != RCTL_REPLACE)
}
}
}
}
/* allocate what we might need before potentially grabbing p_lock */
if (flags & RCTL_USE_RECIPIENT_PID) {
/* case for manipulating rctl values on other procs */
/* cannot be other pid on process rctls */
goto rctlsys_out;
}
/*
* must have privilege to manipulate controls
* on other processes
*/
goto rctlsys_out;
}
if (!pp) {
goto rctlsys_out;
}
/*
* idle or zombie procs have either not yet
* set up their rctls or have already done
* their rctl_set_tearoff's.
*/
goto rctlsys_out;
}
/*
* hold this pp's p_lock to ensure that
* it does not do it's rctl_set_tearoff
* If we did not do this, we could
* potentially add rctls to the entity
* with a recipient that is a process
* that has exited.
*/
/*
* We know that curproc's task, project,
* and zone pointers will not change
* because functions that change them
* call holdlwps(SHOLDFORK1) first.
*/
/*
* verify that the found pp is in the
* current task. If it is, then it
* is also within the current project
* and zone.
*/
goto rctlsys_out;
}
} else {
/* for manipulating rctl values on this proc */
}
} else {
/* RCTL_USE_RECIPIENT_PID not set, use this proc */
}
} else {
/* privileged controls have no recipient pid */
}
nval->rcv_firing_time = 0;
if (action == RCTL_REPLACE) {
goto rctlsys_out;
}
goto rctlsys_out;
}
if (!(flags & RCTL_USE_RECIPIENT_PID)) {
}
} else {
}
/*
* Find the real value we're attempting to replace on the
* sequence, rather than trusting the one delivered from
* userland.
*/
goto rctlsys_out;
}
do {
break;
else
goto rctlsys_out;
}
/*
* System controls are immutable.
*/
goto rctlsys_out;
}
/*
* Only privileged processes in the global zone can modify
* privileged rctls of type RCENTITY_ZONE; replacing privileged
* controls with basic ones are not allowed either. Lowering a
* lowerable one might be OK for privileged processes in a
* non-global zone, but lowerable rctls probably don't make
* sense for zones (hence, not modifiable from within a zone).
*/
goto rctlsys_out;
}
/*
* Must be privileged to replace a privileged control with
* a basic one.
*/
goto rctlsys_out;
}
/*
* Must have lowerable global property for non-privileged
* to lower the value of a privileged control; otherwise must
* have sufficient privileges to modify privileged controls
* at all.
*/
goto rctlsys_out;
}
goto rctlsys_out;
}
/* ensure that nval is not freed */
} else if (action == RCTL_INSERT) {
/*
* System controls are immutable.
*/
goto rctlsys_out;
}
/*
* Only privileged processes in the global zone may add
* privileged zone.* rctls. Only privileged processes
* may add other privileged rctls.
*/
goto rctlsys_out;
}
}
/*
* Only one basic control is allowed per rctl.
* If a basic control is being inserted, delete
* any other basic control.
*/
do {
pp);
pp) != 0)
break;
}
== 0);
}
goto rctlsys_out;
}
/* ensure that nval is not freed */
} else {
/*
* RCTL_DELETE
*/
goto rctlsys_out;
}
goto rctlsys_out;
}
}
goto rctlsys_out;
}
}
if (pp)
/* only free nval if we did not rctl_local_insert it */
if (nval)
return (ret);
}
static long
{
char *kbuf;
}
return (kbufsz);
}
static long
{
char *kname;
}
switch (flags) {
case RCTLCTL_GET:
}
}
break;
case RCTLCTL_SET:
}
}
}
}
break;
default:
}
return (0);
}
/*
* The arbitrary maximum number of rctl_opaque_t that we can pass to
* rctl_projset().
*/
static long
{
char *kname;
int error = 0;
int count;
}
if (size > RCTL_PROJSET_MAXSIZE) {
}
}
/* If not a project entity then exit */
}
}
/* Allocate an array large enough for all resource control blocks */
RBX_FROM_BLK | RBX_VAL);
/*
* Project entity resource control values should always
* be privileged
*/
/*
* This is a project entity; we do not set
* rcv_action_recipient or rcv_action_recip_pid
*/
new_val->rcv_firing_time = 0;
/*
* alloc_val is left largely uninitialized, it
* is a pre-allocated rctl_val_t which is used
* later in rctl_local_replace_all() /
* rctl_local_insert_all().
*/
} else {
}
}
} else {
}
if (error) {
/*
* We will have the same number of items in the alloc_values
* linked list, as we have in new_values. However, we remain
* cautious, and teardown the linked lists individually.
*/
while (new_values != NULL) {
}
while (alloc_values != NULL) {
}
}
/*
* We take the p_lock here to maintain consistency with other functions
* - rctlsys_get() and rctlsys_set()
*/
if (flags & TASK_PROJ_PURGE) {
curproc);
} else {
curproc);
}
return (0);
}
long
{
switch (code) {
case 0:
case 1:
case 2:
/*
* Private call for rctl_walk(3C).
*/
case 3:
/*
* Private code for rctladm(1M): "rctlctl".
*/
case 4:
/*
* Private code for setproject(3PROJECT).
*/
default:
}
}