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