xref: /onnv-gate/usr/src/uts/common/disp/class.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/systm.h>
31*0Sstevel@tonic-gate #include <sys/cmn_err.h>
32*0Sstevel@tonic-gate #include <sys/class.h>
33*0Sstevel@tonic-gate #include <sys/kmem.h>
34*0Sstevel@tonic-gate #include <sys/cred.h>
35*0Sstevel@tonic-gate #include <sys/proc.h>
36*0Sstevel@tonic-gate #include <sys/procset.h>
37*0Sstevel@tonic-gate #include <sys/modctl.h>
38*0Sstevel@tonic-gate #include <sys/disp.h>
39*0Sstevel@tonic-gate #include <sys/sysmacros.h>
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate static int getcidbyname_locked(char *, id_t *);
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate /*
44*0Sstevel@tonic-gate  * Allocate a cid given a class name if one is not already allocated.
45*0Sstevel@tonic-gate  * Returns 0 if the cid was already exists or if the allocation of a new
46*0Sstevel@tonic-gate  * cid was successful. Nonzero return indicates error.
47*0Sstevel@tonic-gate  */
48*0Sstevel@tonic-gate int
49*0Sstevel@tonic-gate alloc_cid(char *clname, id_t *cidp)
50*0Sstevel@tonic-gate {
51*0Sstevel@tonic-gate 	sclass_t *clp;
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&class_lock));
54*0Sstevel@tonic-gate 
55*0Sstevel@tonic-gate 	/*
56*0Sstevel@tonic-gate 	 * If the clname doesn't already have a cid, allocate one.
57*0Sstevel@tonic-gate 	 */
58*0Sstevel@tonic-gate 	if (getcidbyname_locked(clname, cidp) != 0) {
59*0Sstevel@tonic-gate 		/*
60*0Sstevel@tonic-gate 		 * Allocate a class entry and a lock for it.
61*0Sstevel@tonic-gate 		 */
62*0Sstevel@tonic-gate 		for (clp = sclass; clp < &sclass[nclass]; clp++)
63*0Sstevel@tonic-gate 			if (clp->cl_name[0] == '\0' && clp->cl_lock == NULL)
64*0Sstevel@tonic-gate 				break;
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate 		if (clp == &sclass[nclass]) {
67*0Sstevel@tonic-gate 			return (ENOSPC);
68*0Sstevel@tonic-gate 		}
69*0Sstevel@tonic-gate 		*cidp = clp - &sclass[0];
70*0Sstevel@tonic-gate 		clp->cl_lock = kmem_alloc(sizeof (krwlock_t), KM_SLEEP);
71*0Sstevel@tonic-gate 		clp->cl_name = kmem_alloc(strlen(clname) + 1, KM_SLEEP);
72*0Sstevel@tonic-gate 		(void) strcpy(clp->cl_name, clname);
73*0Sstevel@tonic-gate 		rw_init(clp->cl_lock, NULL, RW_DEFAULT, NULL);
74*0Sstevel@tonic-gate 	}
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate 	/*
77*0Sstevel@tonic-gate 	 * At this point, *cidp will contain the index into the class
78*0Sstevel@tonic-gate 	 * array for the given class name.
79*0Sstevel@tonic-gate 	 */
80*0Sstevel@tonic-gate 	return (0);
81*0Sstevel@tonic-gate }
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate int
84*0Sstevel@tonic-gate scheduler_load(char *clname, sclass_t *clp)
85*0Sstevel@tonic-gate {
86*0Sstevel@tonic-gate 	int rv = 0;
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	if (LOADABLE_SCHED(clp)) {
89*0Sstevel@tonic-gate 		rw_enter(clp->cl_lock, RW_READER);
90*0Sstevel@tonic-gate 		if (!SCHED_INSTALLED(clp)) {
91*0Sstevel@tonic-gate 			rw_exit(clp->cl_lock);
92*0Sstevel@tonic-gate 			if (modload("sched", clname) == -1)
93*0Sstevel@tonic-gate 				return (EINVAL);
94*0Sstevel@tonic-gate 			rw_enter(clp->cl_lock, RW_READER);
95*0Sstevel@tonic-gate 			/* did we really load a scheduling class? */
96*0Sstevel@tonic-gate 			if (!SCHED_INSTALLED(clp))
97*0Sstevel@tonic-gate 				rv = EINVAL;
98*0Sstevel@tonic-gate 		}
99*0Sstevel@tonic-gate 		rw_exit(clp->cl_lock);
100*0Sstevel@tonic-gate 	}
101*0Sstevel@tonic-gate 	return (rv);
102*0Sstevel@tonic-gate }
103*0Sstevel@tonic-gate 
104*0Sstevel@tonic-gate /*
105*0Sstevel@tonic-gate  * Get class ID given class name.
106*0Sstevel@tonic-gate  */
107*0Sstevel@tonic-gate int
108*0Sstevel@tonic-gate getcid(char *clname, id_t *cidp)
109*0Sstevel@tonic-gate {
110*0Sstevel@tonic-gate 	sclass_t *clp;
111*0Sstevel@tonic-gate 	int retval;
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	mutex_enter(&class_lock);
114*0Sstevel@tonic-gate 	if ((retval = alloc_cid(clname, cidp)) == 0) {
115*0Sstevel@tonic-gate 		clp = &sclass[*cidp];
116*0Sstevel@tonic-gate 		clp->cl_count++;
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate 		/*
119*0Sstevel@tonic-gate 		 * If it returns zero, it's loaded & locked
120*0Sstevel@tonic-gate 		 * or we found a statically installed scheduler
121*0Sstevel@tonic-gate 		 * module.
122*0Sstevel@tonic-gate 		 * If it returns EINVAL, modload() failed when
123*0Sstevel@tonic-gate 		 * it tried to load the module.
124*0Sstevel@tonic-gate 		 */
125*0Sstevel@tonic-gate 		mutex_exit(&class_lock);
126*0Sstevel@tonic-gate 		retval = scheduler_load(clname, clp);
127*0Sstevel@tonic-gate 		mutex_enter(&class_lock);
128*0Sstevel@tonic-gate 
129*0Sstevel@tonic-gate 		clp->cl_count--;
130*0Sstevel@tonic-gate 		if (retval != 0 && clp->cl_count == 0) {
131*0Sstevel@tonic-gate 			/* last guy out of scheduler_load frees the storage */
132*0Sstevel@tonic-gate 			kmem_free(clp->cl_name, strlen(clname) + 1);
133*0Sstevel@tonic-gate 			kmem_free(clp->cl_lock, sizeof (krwlock_t));
134*0Sstevel@tonic-gate 			clp->cl_name = "";
135*0Sstevel@tonic-gate 			clp->cl_lock = (krwlock_t *)NULL;
136*0Sstevel@tonic-gate 		}
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate 	mutex_exit(&class_lock);
139*0Sstevel@tonic-gate 	return (retval);
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate }
142*0Sstevel@tonic-gate 
143*0Sstevel@tonic-gate static int
144*0Sstevel@tonic-gate getcidbyname_locked(char *clname, id_t *cidp)
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate 	sclass_t *clp;
147*0Sstevel@tonic-gate 
148*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&class_lock));
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate 	if (*clname == NULL)
151*0Sstevel@tonic-gate 		return (EINVAL);
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	for (clp = &sclass[0]; clp < &sclass[nclass]; clp++) {
154*0Sstevel@tonic-gate 		if (strcmp(clp->cl_name, clname) == 0) {
155*0Sstevel@tonic-gate 			*cidp = clp - &sclass[0];
156*0Sstevel@tonic-gate 			return (0);
157*0Sstevel@tonic-gate 		}
158*0Sstevel@tonic-gate 	}
159*0Sstevel@tonic-gate 	return (EINVAL);
160*0Sstevel@tonic-gate }
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate /*
163*0Sstevel@tonic-gate  * Lookup a module by name.
164*0Sstevel@tonic-gate  */
165*0Sstevel@tonic-gate int
166*0Sstevel@tonic-gate getcidbyname(char *clname, id_t *cidp)
167*0Sstevel@tonic-gate {
168*0Sstevel@tonic-gate 	int retval;
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate 	mutex_enter(&class_lock);
171*0Sstevel@tonic-gate 	retval = getcidbyname_locked(clname, cidp);
172*0Sstevel@tonic-gate 	mutex_exit(&class_lock);
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	return (retval);
175*0Sstevel@tonic-gate }
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate /*
178*0Sstevel@tonic-gate  * Get the scheduling parameters of the thread pointed to by
179*0Sstevel@tonic-gate  * tp into the buffer pointed to by parmsp.
180*0Sstevel@tonic-gate  */
181*0Sstevel@tonic-gate void
182*0Sstevel@tonic-gate parmsget(kthread_id_t tp, pcparms_t *parmsp)
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate 	parmsp->pc_cid = tp->t_cid;
185*0Sstevel@tonic-gate 	CL_PARMSGET(tp, parmsp->pc_clparms);
186*0Sstevel@tonic-gate }
187*0Sstevel@tonic-gate 
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate /*
190*0Sstevel@tonic-gate  * Check the validity of the scheduling parameters in the buffer
191*0Sstevel@tonic-gate  * pointed to by parmsp.
192*0Sstevel@tonic-gate  * Note that the format of the parameters may be changed by class
193*0Sstevel@tonic-gate  * specific code which we call.
194*0Sstevel@tonic-gate  */
195*0Sstevel@tonic-gate int
196*0Sstevel@tonic-gate parmsin(pcparms_t *parmsp, pc_vaparms_t *vaparmsp)
197*0Sstevel@tonic-gate {
198*0Sstevel@tonic-gate 	if (parmsp->pc_cid >= loaded_classes || parmsp->pc_cid < 1)
199*0Sstevel@tonic-gate 		return (EINVAL);
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate 	/*
202*0Sstevel@tonic-gate 	 * Call the class specific routine to validate class
203*0Sstevel@tonic-gate 	 * specific parameters.
204*0Sstevel@tonic-gate 	 * The input parameters are either in a pcparms structure (PC_SETPARMS)
205*0Sstevel@tonic-gate 	 * or in a variable parameter structure (PC_SETXPARMS). In the
206*0Sstevel@tonic-gate 	 * 'PC_SETPARMS' case vaparmsp is a NULL pointer and a CL_PARMSIN()
207*0Sstevel@tonic-gate 	 * routine gets the parameter. Otherwise vaparmsp points to a variable
208*0Sstevel@tonic-gate 	 * parameter structure and a CL_VAPARMSIN() routine gets the parameter.
209*0Sstevel@tonic-gate 	 */
210*0Sstevel@tonic-gate 	if (vaparmsp != NULL)
211*0Sstevel@tonic-gate 		return (CL_VAPARMSIN(&sclass[parmsp->pc_cid],
212*0Sstevel@tonic-gate 		    parmsp->pc_clparms, vaparmsp));
213*0Sstevel@tonic-gate 	else
214*0Sstevel@tonic-gate 		return (CL_PARMSIN(&sclass[parmsp->pc_cid],
215*0Sstevel@tonic-gate 		    parmsp->pc_clparms));
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate /*
220*0Sstevel@tonic-gate  * Call the class specific code to do the required processing
221*0Sstevel@tonic-gate  * before the scheduling parameters are copied out to the user.
222*0Sstevel@tonic-gate  * Note that the format of the parameters may be changed by the
223*0Sstevel@tonic-gate  * class specific code.
224*0Sstevel@tonic-gate  */
225*0Sstevel@tonic-gate int
226*0Sstevel@tonic-gate parmsout(pcparms_t *parmsp, pc_vaparms_t *vaparmsp)
227*0Sstevel@tonic-gate {
228*0Sstevel@tonic-gate 	return (CL_PARMSOUT(&sclass[parmsp->pc_cid], parmsp->pc_clparms,
229*0Sstevel@tonic-gate 		vaparmsp));
230*0Sstevel@tonic-gate }
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate 
233*0Sstevel@tonic-gate /*
234*0Sstevel@tonic-gate  * Set the scheduling parameters of the thread pointed to by
235*0Sstevel@tonic-gate  * targtp to those specified in the pcparms structure pointed
236*0Sstevel@tonic-gate  * to by parmsp.  If reqtp is non-NULL it points to the thread
237*0Sstevel@tonic-gate  * that initiated the request for the parameter change and indicates
238*0Sstevel@tonic-gate  * that our caller wants us to verify that the requesting thread
239*0Sstevel@tonic-gate  * has the appropriate permissions.
240*0Sstevel@tonic-gate  */
241*0Sstevel@tonic-gate int
242*0Sstevel@tonic-gate parmsset(pcparms_t *parmsp, kthread_id_t targtp)
243*0Sstevel@tonic-gate {
244*0Sstevel@tonic-gate 	caddr_t	clprocp;
245*0Sstevel@tonic-gate 	int	error;
246*0Sstevel@tonic-gate 	cred_t	*reqpcredp;
247*0Sstevel@tonic-gate 	proc_t	*reqpp = ttoproc(curthread);
248*0Sstevel@tonic-gate 	proc_t	*targpp = ttoproc(targtp);
249*0Sstevel@tonic-gate 	id_t	oldcid;
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
252*0Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&targpp->p_lock));
253*0Sstevel@tonic-gate 	if (reqpp != NULL) {
254*0Sstevel@tonic-gate 		mutex_enter(&reqpp->p_crlock);
255*0Sstevel@tonic-gate 		crhold(reqpcredp = reqpp->p_cred);
256*0Sstevel@tonic-gate 		mutex_exit(&reqpp->p_crlock);
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 		/*
259*0Sstevel@tonic-gate 		 * Check basic permissions.
260*0Sstevel@tonic-gate 		 */
261*0Sstevel@tonic-gate 		if (!prochasprocperm(targpp, reqpp, reqpcredp)) {
262*0Sstevel@tonic-gate 			crfree(reqpcredp);
263*0Sstevel@tonic-gate 			return (EPERM);
264*0Sstevel@tonic-gate 		}
265*0Sstevel@tonic-gate 	} else {
266*0Sstevel@tonic-gate 		reqpcredp = NULL;
267*0Sstevel@tonic-gate 	}
268*0Sstevel@tonic-gate 
269*0Sstevel@tonic-gate 	if (parmsp->pc_cid != targtp->t_cid) {
270*0Sstevel@tonic-gate 		void	*bufp = NULL;
271*0Sstevel@tonic-gate 		/*
272*0Sstevel@tonic-gate 		 * Target thread must change to new class.
273*0Sstevel@tonic-gate 		 */
274*0Sstevel@tonic-gate 		clprocp = (caddr_t)targtp->t_cldata;
275*0Sstevel@tonic-gate 		oldcid  = targtp->t_cid;
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 		/*
278*0Sstevel@tonic-gate 		 * Purpose: allow scheduling class to veto moves
279*0Sstevel@tonic-gate 		 * to other classes. All the classes, except FSS,
280*0Sstevel@tonic-gate 		 * do nothing except returning 0.
281*0Sstevel@tonic-gate 		 */
282*0Sstevel@tonic-gate 		error = CL_CANEXIT(targtp, reqpcredp);
283*0Sstevel@tonic-gate 		if (error) {
284*0Sstevel@tonic-gate 			/*
285*0Sstevel@tonic-gate 			 * Not allowed to leave the class, so return error.
286*0Sstevel@tonic-gate 			 */
287*0Sstevel@tonic-gate 			crfree(reqpcredp);
288*0Sstevel@tonic-gate 			return (error);
289*0Sstevel@tonic-gate 		} else {
290*0Sstevel@tonic-gate 			/*
291*0Sstevel@tonic-gate 			 * Pre-allocate scheduling class data.
292*0Sstevel@tonic-gate 			 */
293*0Sstevel@tonic-gate 			if (CL_ALLOC(&bufp, parmsp->pc_cid, KM_NOSLEEP) != 0) {
294*0Sstevel@tonic-gate 				error = ENOMEM; /* no memory available */
295*0Sstevel@tonic-gate 				crfree(reqpcredp);
296*0Sstevel@tonic-gate 				return (error);
297*0Sstevel@tonic-gate 			} else {
298*0Sstevel@tonic-gate 				error = CL_ENTERCLASS(targtp, parmsp->pc_cid,
299*0Sstevel@tonic-gate 				    parmsp->pc_clparms, reqpcredp, bufp);
300*0Sstevel@tonic-gate 				crfree(reqpcredp);
301*0Sstevel@tonic-gate 				if (error) {
302*0Sstevel@tonic-gate 					CL_FREE(parmsp->pc_cid, bufp);
303*0Sstevel@tonic-gate 					return (error);
304*0Sstevel@tonic-gate 				}
305*0Sstevel@tonic-gate 			}
306*0Sstevel@tonic-gate 		}
307*0Sstevel@tonic-gate 		CL_EXITCLASS(oldcid, clprocp);
308*0Sstevel@tonic-gate 	} else {
309*0Sstevel@tonic-gate 
310*0Sstevel@tonic-gate 		/*
311*0Sstevel@tonic-gate 		 * Not changing class
312*0Sstevel@tonic-gate 		 */
313*0Sstevel@tonic-gate 		error = CL_PARMSSET(targtp, parmsp->pc_clparms,
314*0Sstevel@tonic-gate 					curthread->t_cid, reqpcredp);
315*0Sstevel@tonic-gate 		crfree(reqpcredp);
316*0Sstevel@tonic-gate 		if (error)
317*0Sstevel@tonic-gate 			return (error);
318*0Sstevel@tonic-gate 	}
319*0Sstevel@tonic-gate 	return (0);
320*0Sstevel@tonic-gate }
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate /*
324*0Sstevel@tonic-gate  * Copy all selected class parameters to the user.
325*0Sstevel@tonic-gate  * The parameters are specified by a key.
326*0Sstevel@tonic-gate  */
327*0Sstevel@tonic-gate int
328*0Sstevel@tonic-gate vaparmsout(char *classp, pcparms_t *prmsp, pc_vaparms_t *vaparmsp)
329*0Sstevel@tonic-gate {
330*0Sstevel@tonic-gate 	char	*clname;
331*0Sstevel@tonic-gate 
332*0Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
333*0Sstevel@tonic-gate 
334*0Sstevel@tonic-gate 	if (classp != NULL)
335*0Sstevel@tonic-gate 		return (CL_VAPARMSOUT(&sclass[prmsp->pc_cid],
336*0Sstevel@tonic-gate 		    prmsp->pc_clparms, vaparmsp));
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	switch (vaparmsp->pc_vaparmscnt) {
339*0Sstevel@tonic-gate 	case 0:
340*0Sstevel@tonic-gate 		return (0);
341*0Sstevel@tonic-gate 	case 1:
342*0Sstevel@tonic-gate 		break;
343*0Sstevel@tonic-gate 	default:
344*0Sstevel@tonic-gate 		return (EINVAL);
345*0Sstevel@tonic-gate 	}
346*0Sstevel@tonic-gate 
347*0Sstevel@tonic-gate 	if (vaparmsp->pc_parms[0].pc_key != PC_KY_CLNAME)
348*0Sstevel@tonic-gate 		return (EINVAL);
349*0Sstevel@tonic-gate 
350*0Sstevel@tonic-gate 	clname = sclass[prmsp->pc_cid].cl_name;
351*0Sstevel@tonic-gate 	if (copyout(clname, (void *)(uintptr_t)vaparmsp->pc_parms[0].pc_parm,
352*0Sstevel@tonic-gate 	    MIN(strlen(clname) + 1, PC_CLNMSZ)))
353*0Sstevel@tonic-gate 		return (EFAULT);
354*0Sstevel@tonic-gate 
355*0Sstevel@tonic-gate 	return (0);
356*0Sstevel@tonic-gate }
357