xref: /titanic_41/usr/src/uts/common/avs/ns/solaris/nskernd.c (revision 9c9af2590af49bb395bc8d2eace0f2d4ea16d165)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/ksynch.h>
28 #include <sys/errno.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 
32 #include "../nsctl.h"
33 #include "../nsctl/nsc_ioctl.h"
34 #include "nskernd.h"
35 
36 void *proc_nskernd;
37 int nskernd_iscluster;
38 
39 static kmutex_t nskernd_lock;
40 
41 static kcondvar_t nskernd_ask_cv;
42 static kcondvar_t nskernd_k_cv;
43 static kcondvar_t nskernd_u_cv;
44 
45 static volatile int nskernd_k_wait;
46 static volatile int nskernd_u_wait;
47 
48 static int nskernd_norun;
49 
50 static volatile int nskernd_ask;
51 static struct nskernd nskernd_kdata;
52 
53 void
54 nskernd_init(void)
55 {
56 	mutex_init(&nskernd_lock, NULL, MUTEX_DRIVER, NULL);
57 	cv_init(&nskernd_ask_cv, NULL, CV_DRIVER, NULL);
58 	cv_init(&nskernd_k_cv, NULL, CV_DRIVER, NULL);
59 	cv_init(&nskernd_u_cv, NULL, CV_DRIVER, NULL);
60 
61 	nskernd_norun = 0;
62 }
63 
64 
65 void
66 nskernd_deinit(void)
67 {
68 	mutex_destroy(&nskernd_lock);
69 	cv_destroy(&nskernd_ask_cv);
70 	cv_destroy(&nskernd_k_cv);
71 	cv_destroy(&nskernd_u_cv);
72 }
73 
74 
75 static int
76 nskernd_start(const int iscluster)
77 {
78 	int rc = 0;
79 
80 	mutex_enter(&nskernd_lock);
81 
82 	if (proc_nskernd != NULL) {
83 		rc = 1;
84 	} else if (nskernd_norun != 0) {
85 		rc = 2;
86 	} else {
87 		(void) drv_getparm(UPROCP, (void *)&proc_nskernd);
88 		nskernd_iscluster = iscluster;
89 	}
90 
91 	mutex_exit(&nskernd_lock);
92 
93 	return (rc);
94 }
95 
96 
97 /*
98  * must be called with nskernd_lock held.
99  */
100 void
101 nskernd_cleanup(void)
102 {
103 	proc_nskernd = NULL;
104 	cv_broadcast(&nskernd_ask_cv);
105 	cv_broadcast(&nskernd_k_cv);
106 }
107 
108 
109 void
110 nskernd_stop(void)
111 {
112 	mutex_enter(&nskernd_lock);
113 
114 	if (proc_nskernd == NULL) {
115 		nskernd_norun = 1;
116 		mutex_exit(&nskernd_lock);
117 		return;
118 	}
119 
120 	while (nskernd_u_wait == 0) {
121 		nskernd_k_wait++;
122 		cv_wait(&nskernd_k_cv, &nskernd_lock);
123 		nskernd_k_wait--;
124 
125 		if (proc_nskernd == NULL) {
126 			mutex_exit(&nskernd_lock);
127 			return;
128 		}
129 	}
130 
131 	nskernd_kdata.command = NSKERND_STOP;
132 	nskernd_kdata.data1 = (uint64_t)1;	/* kernel has done cleanup */
133 
134 	nskernd_cleanup();
135 
136 	cv_signal(&nskernd_u_cv);
137 	mutex_exit(&nskernd_lock);
138 }
139 
140 
141 int
142 nskernd_get(struct nskernd *nskp)
143 {
144 	mutex_enter(&nskernd_lock);
145 
146 	if (proc_nskernd == NULL) {
147 		mutex_exit(&nskernd_lock);
148 		return (ENXIO);
149 	}
150 
151 	while (nskernd_u_wait == 0 || nskernd_ask) {
152 		nskernd_k_wait++;
153 		cv_wait(&nskernd_k_cv, &nskernd_lock);
154 		nskernd_k_wait--;
155 
156 		if (proc_nskernd == NULL) {
157 			mutex_exit(&nskernd_lock);
158 			return (ENXIO);
159 		}
160 	}
161 
162 	bcopy(nskp, &nskernd_kdata, sizeof (*nskp));
163 	nskernd_ask++;
164 
165 	cv_signal(&nskernd_u_cv);
166 
167 	cv_wait(&nskernd_ask_cv, &nskernd_lock);
168 
169 	if (proc_nskernd == NULL) {
170 		nskernd_ask--;
171 		mutex_exit(&nskernd_lock);
172 		return (ENXIO);
173 	}
174 
175 	bcopy(&nskernd_kdata, nskp, sizeof (*nskp));
176 	nskernd_ask--;
177 
178 	if (nskernd_k_wait > 0)
179 		cv_signal(&nskernd_k_cv);
180 
181 	mutex_exit(&nskernd_lock);
182 	return (0);
183 }
184 
185 
186 int
187 nskernd_command(intptr_t arg, int mode, int *rvalp)
188 {
189 	struct nskernd *udata = NULL;
190 	uint64_t arg1, arg2;
191 	int rc;
192 
193 	*rvalp = 0;
194 	rc = 0;
195 
196 	udata = kmem_alloc(sizeof (*udata), KM_SLEEP);
197 	if (ddi_copyin((void *)arg, udata, sizeof (*udata), mode) < 0) {
198 		kmem_free(udata, sizeof (*udata));
199 		return (EFAULT);
200 	}
201 
202 	switch (udata->command) {
203 	case NSKERND_START:		/* User program start */
204 		*rvalp = nskernd_start(udata->data1);
205 		break;
206 
207 	case NSKERND_STOP:		/* User program requesting stop */
208 		mutex_enter(&nskernd_lock);
209 		nskernd_cleanup();
210 		mutex_exit(&nskernd_lock);
211 		break;
212 
213 	case NSKERND_WAIT:
214 		mutex_enter(&nskernd_lock);
215 
216 		bcopy(udata, &nskernd_kdata, sizeof (*udata));
217 
218 		if (nskernd_ask > 0)
219 			cv_signal(&nskernd_ask_cv);
220 
221 		nskernd_u_wait++;
222 
223 		if (cv_wait_sig(&nskernd_u_cv, &nskernd_lock) != 0) {
224 			/*
225 			 * woken by cv_signal() or cv_broadcast()
226 			 */
227 			bcopy(&nskernd_kdata, udata, sizeof (*udata));
228 		} else {
229 			/*
230 			 * signal - the user process has blocked all
231 			 * signals except for SIGTERM and the
232 			 * uncatchables, so the process is about to die
233 			 * and we need to clean up.
234 			 */
235 			udata->command = NSKERND_STOP;
236 			udata->data1 = (uint64_t)1;	 /* cleanup done */
237 
238 			nskernd_cleanup();
239 		}
240 
241 		nskernd_u_wait--;
242 
243 		mutex_exit(&nskernd_lock);
244 
245 		if (ddi_copyout(udata, (void *)arg,
246 		    sizeof (*udata), mode) < 0) {
247 			rc = EFAULT;
248 			break;
249 		}
250 
251 		break;
252 
253 	case NSKERND_NEWLWP:
254 		/* save kmem by freeing the udata structure */
255 		arg1 = udata->data1;
256 		kmem_free(udata, sizeof (*udata));
257 		udata = NULL;
258 		nsc_runlwp(arg1);
259 		break;
260 
261 	case NSKERND_LOCK:
262 		/* save kmem by freeing the udata structure */
263 		arg1 = udata->data1;
264 		arg2 = udata->data2;
265 		kmem_free(udata, sizeof (*udata));
266 		udata = NULL;
267 		nsc_lockchild(arg1, arg2);
268 		break;
269 
270 	default:
271 		cmn_err(CE_WARN, "nskernd: unknown command %d", udata->command);
272 		rc = EINVAL;
273 		break;
274 	}
275 
276 	if (udata != NULL) {
277 		kmem_free(udata, sizeof (*udata));
278 		udata = NULL;
279 	}
280 
281 	return (rc);
282 }
283 
284 /*
285  * This function is included for SV ioctl processing only.
286  */
287 
288 int
289 nskernd_isdaemon(void)
290 {
291 	void *this_proc;
292 
293 	if (proc_nskernd == NULL)
294 		return (0);
295 	if (drv_getparm(UPROCP, (void *)&this_proc) != 0)
296 		return (0);
297 	return (proc_nskernd == this_proc);
298 }
299