view usr/src/uts/common/disp/class.c @ 7887:f9ded24b041a

[fmac-discuss] [PATCH] Fix more cstyle issues Fix more cstyle issues introduced by prior patches, in particular the hasprocperm patch and the secctx patch. uts/common/syscall/lgrpsys.c is still not clean with regard to continuation indentation but the remaining warnings were not introduced by our patches.
author Stephen Smalley <sds@tycho.nsa.gov>
date Fri, 17 Oct 2008 13:28:50 -0400
parents e3677dd00778
children
line wrap: on
line source

/*
 * 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
 * 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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/types.h>
#include <sys/systm.h>
#include <sys/cmn_err.h>
#include <sys/class.h>
#include <sys/kmem.h>
#include <sys/cred.h>
#include <sys/fmac/av_permissions.h>
#include <sys/proc.h>
#include <sys/procset.h>
#include <sys/modctl.h>
#include <sys/disp.h>
#include <sys/sysmacros.h>
#include <sys/schedctl.h>

static int getcidbyname_locked(char *, id_t *);

/*
 * Allocate a cid given a class name if one is not already allocated.
 * Returns 0 if the cid was already exists or if the allocation of a new
 * cid was successful. Nonzero return indicates error.
 */
int
alloc_cid(char *clname, id_t *cidp)
{
	sclass_t *clp;

	ASSERT(MUTEX_HELD(&class_lock));

	/*
	 * If the clname doesn't already have a cid, allocate one.
	 */
	if (getcidbyname_locked(clname, cidp) != 0) {
		/*
		 * Allocate a class entry and a lock for it.
		 */
		for (clp = sclass; clp < &sclass[nclass]; clp++)
			if (clp->cl_name[0] == '\0' && clp->cl_lock == NULL)
				break;

		if (clp == &sclass[nclass]) {
			return (ENOSPC);
		}
		*cidp = clp - &sclass[0];
		clp->cl_lock = kmem_alloc(sizeof (krwlock_t), KM_SLEEP);
		clp->cl_name = kmem_alloc(strlen(clname) + 1, KM_SLEEP);
		(void) strcpy(clp->cl_name, clname);
		rw_init(clp->cl_lock, NULL, RW_DEFAULT, NULL);
	}

	/*
	 * At this point, *cidp will contain the index into the class
	 * array for the given class name.
	 */
	return (0);
}

int
scheduler_load(char *clname, sclass_t *clp)
{
	int rv = 0;

	if (LOADABLE_SCHED(clp)) {
		rw_enter(clp->cl_lock, RW_READER);
		if (!SCHED_INSTALLED(clp)) {
			rw_exit(clp->cl_lock);
			if (modload("sched", clname) == -1)
				return (EINVAL);
			rw_enter(clp->cl_lock, RW_READER);
			/* did we really load a scheduling class? */
			if (!SCHED_INSTALLED(clp))
				rv = EINVAL;
		}
		rw_exit(clp->cl_lock);
	}
	return (rv);
}

/*
 * Get class ID given class name.
 */
int
getcid(char *clname, id_t *cidp)
{
	sclass_t *clp;
	int retval;

	mutex_enter(&class_lock);
	if ((retval = alloc_cid(clname, cidp)) == 0) {
		clp = &sclass[*cidp];
		clp->cl_count++;

		/*
		 * If it returns zero, it's loaded & locked
		 * or we found a statically installed scheduler
		 * module.
		 * If it returns EINVAL, modload() failed when
		 * it tried to load the module.
		 */
		mutex_exit(&class_lock);
		retval = scheduler_load(clname, clp);
		mutex_enter(&class_lock);

		clp->cl_count--;
		if (retval != 0 && clp->cl_count == 0) {
			/* last guy out of scheduler_load frees the storage */
			kmem_free(clp->cl_name, strlen(clname) + 1);
			kmem_free(clp->cl_lock, sizeof (krwlock_t));
			clp->cl_name = "";
			clp->cl_lock = (krwlock_t *)NULL;
		}
	}
	mutex_exit(&class_lock);
	return (retval);

}

static int
getcidbyname_locked(char *clname, id_t *cidp)
{
	sclass_t *clp;

	ASSERT(MUTEX_HELD(&class_lock));

	if (*clname == NULL)
		return (EINVAL);

	for (clp = &sclass[0]; clp < &sclass[nclass]; clp++) {
		if (strcmp(clp->cl_name, clname) == 0) {
			*cidp = clp - &sclass[0];
			return (0);
		}
	}
	return (EINVAL);
}

/*
 * Lookup a module by name.
 */
int
getcidbyname(char *clname, id_t *cidp)
{
	int retval;

	mutex_enter(&class_lock);
	retval = getcidbyname_locked(clname, cidp);
	mutex_exit(&class_lock);

	return (retval);
}

/*
 * Get the scheduling parameters of the thread pointed to by
 * tp into the buffer pointed to by parmsp.
 */
void
parmsget(kthread_t *tp, pcparms_t *parmsp)
{
	parmsp->pc_cid = tp->t_cid;
	CL_PARMSGET(tp, parmsp->pc_clparms);
}


/*
 * Check the validity of the scheduling parameters in the buffer
 * pointed to by parmsp.
 * Note that the format of the parameters may be changed by class
 * specific code which we call.
 */
int
parmsin(pcparms_t *parmsp, pc_vaparms_t *vaparmsp)
{
	if (parmsp->pc_cid >= loaded_classes || parmsp->pc_cid < 1)
		return (EINVAL);

	/*
	 * Call the class specific routine to validate class
	 * specific parameters.
	 * The input parameters are either in a pcparms structure (PC_SETPARMS)
	 * or in a variable parameter structure (PC_SETXPARMS). In the
	 * 'PC_SETPARMS' case vaparmsp is a NULL pointer and a CL_PARMSIN()
	 * routine gets the parameter. Otherwise vaparmsp points to a variable
	 * parameter structure and a CL_VAPARMSIN() routine gets the parameter.
	 */
	if (vaparmsp != NULL)
		return (CL_VAPARMSIN(&sclass[parmsp->pc_cid],
		    parmsp->pc_clparms, vaparmsp));
	else
		return (CL_PARMSIN(&sclass[parmsp->pc_cid],
		    parmsp->pc_clparms));
}


/*
 * Call the class specific code to do the required processing
 * before the scheduling parameters are copied out to the user.
 * Note that the format of the parameters may be changed by the
 * class specific code.
 */
int
parmsout(pcparms_t *parmsp, pc_vaparms_t *vaparmsp)
{
	return (CL_PARMSOUT(&sclass[parmsp->pc_cid], parmsp->pc_clparms,
	    vaparmsp));
}


/*
 * Set the scheduling parameters of the thread pointed to by
 * targtp to those specified in the pcparms structure pointed
 * to by parmsp.  If reqtp is non-NULL it points to the thread
 * that initiated the request for the parameter change and indicates
 * that our caller wants us to verify that the requesting thread
 * has the appropriate permissions.
 */
int
parmsset(pcparms_t *parmsp, kthread_t *targtp)
{
	caddr_t	clprocp;
	int	error;
	cred_t	*reqpcredp;
	proc_t	*reqpp = ttoproc(curthread);
	proc_t	*targpp = ttoproc(targtp);
	id_t	oldcid;

	ASSERT(MUTEX_HELD(&pidlock));
	ASSERT(MUTEX_HELD(&targpp->p_lock));
	if (reqpp != NULL) {
		mutex_enter(&reqpp->p_crlock);
		crhold(reqpcredp = reqpp->p_cred);
		mutex_exit(&reqpp->p_crlock);

		/*
		 * Check basic permissions.
		 */
		if (!prochasprocperm(targpp, reqpp, reqpcredp,
		    PROCESS__SETSCHED)) {
			crfree(reqpcredp);
			return (EPERM);
		}
	} else {
		reqpcredp = NULL;
	}

	if (parmsp->pc_cid != targtp->t_cid) {
		void	*bufp = NULL;
		/*
		 * Target thread must change to new class.
		 */
		clprocp = (caddr_t)targtp->t_cldata;
		oldcid  = targtp->t_cid;

		/*
		 * Purpose: allow scheduling class to veto moves
		 * to other classes. All the classes, except FSS,
		 * do nothing except returning 0.
		 */
		error = CL_CANEXIT(targtp, reqpcredp);
		if (error) {
			/*
			 * Not allowed to leave the class, so return error.
			 */
			crfree(reqpcredp);
			return (error);
		} else {
			/*
			 * Pre-allocate scheduling class data.
			 */
			if (CL_ALLOC(&bufp, parmsp->pc_cid, KM_NOSLEEP) != 0) {
				error = ENOMEM; /* no memory available */
				crfree(reqpcredp);
				return (error);
			} else {
				error = CL_ENTERCLASS(targtp, parmsp->pc_cid,
				    parmsp->pc_clparms, reqpcredp, bufp);
				crfree(reqpcredp);
				if (error) {
					CL_FREE(parmsp->pc_cid, bufp);
					return (error);
				}
			}
		}
		CL_EXITCLASS(oldcid, clprocp);
	} else {

		/*
		 * Not changing class
		 */
		error = CL_PARMSSET(targtp, parmsp->pc_clparms,
		    curthread->t_cid, reqpcredp);
		crfree(reqpcredp);
		if (error)
			return (error);
	}
	schedctl_set_cidpri(targtp);
	return (0);
}


/*
 * Copy all selected class parameters to the user.
 * The parameters are specified by a key.
 */
int
vaparmsout(char *classp, pcparms_t *prmsp, pc_vaparms_t *vaparmsp,
    uio_seg_t seg)
{
	char	*clname;

	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));

	if (classp != NULL)
		return (CL_VAPARMSOUT(&sclass[prmsp->pc_cid],
		    prmsp->pc_clparms, vaparmsp));

	switch (vaparmsp->pc_vaparmscnt) {
	case 0:
		return (0);
	case 1:
		break;
	default:
		return (EINVAL);
	}

	if (vaparmsp->pc_parms[0].pc_key != PC_KY_CLNAME)
		return (EINVAL);

	clname = sclass[prmsp->pc_cid].cl_name;
	if ((seg == UIO_USERSPACE ? copyout : kcopy)(clname,
	    (void *)(uintptr_t)vaparmsp->pc_parms[0].pc_parm,
	    MIN(strlen(clname) + 1, PC_CLNMSZ)))
		return (EFAULT);

	return (0);
}