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
nskernd_init(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
nskernd_deinit(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
nskernd_start(const int iscluster)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
nskernd_cleanup(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
nskernd_stop(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
nskernd_get(struct nskernd * nskp)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
nskernd_command(intptr_t arg,int mode,int * rvalp)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
nskernd_isdaemon(void)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