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/cmn_err.h> 29 #include <sys/kmem.h> 30 #include <sys/stat.h> 31 #include <sys/file.h> 32 #include <sys/cred.h> 33 #include <sys/conf.h> 34 #include <sys/modctl.h> 35 #include <sys/errno.h> 36 37 #include <sys/unistat/spcs_s.h> 38 #include <sys/unistat/spcs_s_k.h> 39 #include <sys/unistat/spcs_errors.h> 40 41 #ifdef _SunOS_2_6 42 /* 43 * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we 44 * define enum_t here as it is all we need from rpc/types.h 45 * anyway and make it look like we included it. Yuck. 46 */ 47 #define _RPC_TYPES_H 48 typedef int enum_t; 49 #else 50 #ifndef DS_DDICT 51 #include <rpc/types.h> 52 #endif 53 #endif /* _SunOS_2_6 */ 54 55 #ifndef DS_DDICT 56 #include <rpc/auth.h> 57 #include <rpc/svc.h> 58 #include <rpc/xdr.h> 59 #else 60 #include "../contract.h" 61 #endif 62 63 #include <sys/ddi.h> 64 65 #include <sys/nsc_thread.h> 66 #include <sys/nsctl/nsctl.h> 67 68 #include <sys/nsctl/nsvers.h> 69 70 #include "rdc_io.h" 71 #include "rdc_stub.h" 72 #include "rdc_ioctl.h" 73 #include "rdcsrv.h" 74 75 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 76 static void rdcsrv_xprtclose(const SVCXPRT *xprt); 77 #else /* SunOS 5.8 or later */ 78 /* 79 * SunOS 5.8 or later. 80 * 81 * RDC callout table 82 * 83 * This table is used by svc_getreq to dispatch a request with a given 84 * prog/vers pair to an approriate service provider. 85 */ 86 87 static SVC_CALLOUT rdcsrv_sc[] = { 88 { RDC_PROGRAM, RDC_VERS_MIN, RDC_VERS_MAX, rdcstub_dispatch } 89 }; 90 91 static SVC_CALLOUT_TABLE rdcsrv_sct = { 92 sizeof (rdcsrv_sc) / sizeof (rdcsrv_sc[0]), FALSE, rdcsrv_sc 93 }; 94 #endif /* SunOS 5.8 or later */ 95 96 static kmutex_t rdcsrv_lock; 97 98 static int rdcsrv_dup_error; 99 static int rdcsrv_registered; 100 static int rdcsrv_closing; 101 static int rdcsrv_refcnt; 102 long rdc_svc_count = 0; 103 static rdcsrv_t *rdcsrv_disptab; 104 105 /* 106 * Solaris module setup. 107 */ 108 109 extern struct mod_ops mod_miscops; 110 111 static struct modlmisc modlmisc = { 112 &mod_miscops, /* Type of module */ 113 "nws:Remote Mirror kRPC:" ISS_VERSION_STR 114 }; 115 116 static struct modlinkage modlinkage = { 117 MODREV_1, 118 &modlmisc, 119 NULL 120 }; 121 122 123 int 124 _init(void) 125 { 126 int rc; 127 128 mutex_init(&rdcsrv_lock, NULL, MUTEX_DRIVER, NULL); 129 130 if ((rc = mod_install(&modlinkage)) != DDI_SUCCESS) 131 mutex_destroy(&rdcsrv_lock); 132 133 return (rc); 134 } 135 136 137 int 138 _fini(void) 139 { 140 int rc; 141 142 if ((rc = mod_remove(&modlinkage)) == DDI_SUCCESS) 143 mutex_destroy(&rdcsrv_lock); 144 145 return (rc); 146 } 147 148 149 int 150 _info(struct modinfo *modinfop) 151 { 152 return (mod_info(&modlinkage, modinfop)); 153 } 154 155 156 /* 157 * RDC kRPC server stub. 158 */ 159 160 void 161 rdcsrv_noproc(void) 162 { 163 ; 164 } 165 166 167 static int 168 rdcsrv_dispdup(struct svc_req *req, SVCXPRT *xprt) 169 { 170 rdc_disptab_t *disp; 171 struct dupreq *dr; 172 rdcsrv_t *srvp; 173 void (*fn)(); 174 int dupstat; 175 176 srvp = &rdcsrv_disptab[req->rq_vers - RDC_VERS_MIN]; 177 disp = &srvp->disptab[req->rq_proc]; 178 fn = disp->dispfn; 179 180 dupstat = SVC_DUP(xprt, req, 0, 0, &dr); 181 182 switch (dupstat) { 183 case DUP_ERROR: 184 /* svcerr_systemerr does a freeargs */ 185 svcerr_systemerr(xprt); 186 rdcsrv_dup_error++; 187 break; 188 189 case DUP_INPROGRESS: 190 rdcsrv_dup_error++; 191 break; 192 193 case DUP_NEW: 194 case DUP_DROP: 195 (*fn)(xprt, req); 196 SVC_DUPDONE(xprt, dr, 0, 0, DUP_DONE); 197 break; 198 199 case DUP_DONE: 200 break; 201 } 202 203 return (dupstat); 204 } 205 206 207 /* 208 * rdcsrv_dispatch is the dispatcher routine for the RDC RPC protocol 209 */ 210 void 211 rdcsrv_dispatch(struct svc_req *req, SVCXPRT *xprt) 212 { 213 rdc_disptab_t *disp; 214 rdcsrv_t *srvp; 215 216 mutex_enter(&rdcsrv_lock); 217 rdcsrv_refcnt++; 218 219 if (!rdcsrv_registered || rdcsrv_closing || !rdcsrv_disptab) { 220 mutex_exit(&rdcsrv_lock); 221 goto outdisp; 222 } 223 224 mutex_exit(&rdcsrv_lock); 225 226 if ((req->rq_vers < RDC_VERS_MIN) || (req->rq_vers > RDC_VERS_MAX)) { 227 svcerr_noproc(xprt); 228 cmn_err(CE_NOTE, 229 "rdcsrv_dispatch: unknown version %d", 230 req->rq_vers); 231 /* svcerr_noproc does a freeargs on xprt */ 232 goto done; 233 } 234 235 srvp = &rdcsrv_disptab[req->rq_vers - RDC_VERS_MIN]; 236 disp = &srvp->disptab[req->rq_proc]; 237 238 if (req->rq_proc >= srvp->nprocs || 239 disp->dispfn == rdcsrv_noproc) { 240 svcerr_noproc(xprt); 241 cmn_err(CE_NOTE, 242 "rdcsrv_dispatch: bad proc number %d", 243 req->rq_proc); 244 /* svcerr_noproc does a freeargs on xprt */ 245 goto done; 246 } else if (disp->clone) { 247 switch (rdcsrv_dispdup(req, xprt)) { 248 case DUP_ERROR: 249 goto done; 250 /* NOTREACHED */ 251 case DUP_INPROGRESS: 252 goto outdisp; 253 /* NOTREACHED */ 254 default: 255 break; 256 } 257 } else { 258 (*disp->dispfn)(xprt, req); 259 rdc_svc_count++; 260 } 261 262 outdisp: 263 if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) 264 cmn_err(CE_NOTE, "rdcsrv_dispatch: bad freeargs"); 265 done: 266 mutex_enter(&rdcsrv_lock); 267 rdcsrv_refcnt--; 268 mutex_exit(&rdcsrv_lock); 269 } 270 271 272 static int 273 rdcsrv_create(file_t *fp, rdc_svc_args_t *args, int mode) 274 { 275 /*LINTED*/ 276 int rc, error = 0; 277 /*LINTED*/ 278 rpcvers_t vers; 279 struct netbuf addrmask; 280 281 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 282 SVCXPRT *xprt; 283 #else 284 SVCMASTERXPRT *xprt; 285 #endif 286 STRUCT_HANDLE(rdc_svc_args, uap); 287 288 STRUCT_SET_HANDLE(uap, mode, args); 289 290 addrmask.len = STRUCT_FGET(uap, addrmask.len); 291 addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen); 292 addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP); 293 error = ddi_copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf, 294 addrmask.len, mode); 295 if (error) { 296 kmem_free(addrmask.buf, addrmask.maxlen); 297 #ifdef DEBUG 298 cmn_err(CE_WARN, "copyin of addrmask failed %p", (void *) args); 299 #endif 300 return (error); 301 } 302 303 /* 304 * Set rdcstub's dispatch handle to rdcsrv_dispatch 305 */ 306 rdcstub_set_dispatch(rdcsrv_dispatch); 307 308 /* 309 * Create a transport endpoint and create one kernel thread to run the 310 * rdc service loop 311 */ 312 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 313 error = svc_tli_kcreate(fp, RDC_RPC_MAX, 314 STRUCT_FGETP(uap, netid), &addrmask, 315 STRUCT_FGET(uap, nthr), &xprt); 316 #else 317 { 318 #if defined(_SunOS_5_8) 319 struct svcpool_args p; 320 p.id = RDC_SVCPOOL_ID; 321 p.maxthreads = STRUCT_FGET(uap, nthr); 322 p.redline = 0; 323 p.qsize = 0; 324 p.timeout = 0; 325 p.stksize = 0; 326 p.max_same_xprt = 0; 327 328 error = svc_pool_create(&p); 329 if (error) { 330 cmn_err(CE_NOTE, 331 "rdcsrv_create: svc_pool_create failed %d", 332 error); 333 return (error); 334 } 335 #endif 336 error = svc_tli_kcreate(fp, RDC_RPC_MAX, 337 STRUCT_FGETP(uap, netid), &addrmask, 338 &xprt, &rdcsrv_sct, NULL, RDC_SVCPOOL_ID, 339 FALSE); 340 } 341 #endif 342 343 if (error) { 344 cmn_err(CE_NOTE, 345 "rdcsrv_create: svc_tli_kcreate failed %d", 346 error); 347 return (error); 348 } 349 350 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 351 if (xprt == NULL) { 352 cmn_err(CE_NOTE, "xprt in rdcsrv_create is NULL"); 353 } else { 354 /* 355 * Register a cleanup routine in case the transport gets 356 * destroyed. If the registration fails for some reason, 357 * it means that the transport is already being destroyed. 358 * This shouldn't happen, but it's probably not worth a 359 * panic. 360 */ 361 if (!svc_control(xprt, SVCSET_CLOSEPROC, 362 (void *)rdcsrv_xprtclose)) { 363 cmn_err( 364 #ifdef DEBUG 365 CE_PANIC, 366 #else 367 CE_WARN, 368 #endif 369 "rdcsrv_create: couldn't set xprt callback"); 370 371 error = EBADF; 372 goto done; 373 } 374 } 375 376 for (vers = RDC_VERS_MIN; vers <= RDC_VERS_MAX; vers++) { 377 rc = svc_register(xprt, (ulong_t)RDC_PROGRAM, vers, 378 rdcstub_dispatch, 0); 379 if (!rc) { 380 cmn_err(CE_NOTE, 381 "rdcsrv_create: svc_register(%d, %lu) failed", 382 RDC_PROGRAM, vers); 383 384 if (!error) { 385 error = EBADF; 386 } 387 } 388 } 389 #endif /* 5.6 or 5.7 */ 390 391 if (!error) { 392 /* mark as registered with the kRPC subsystem */ 393 rdcsrv_registered = 1; 394 } 395 396 done: 397 return (error); 398 } 399 400 401 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 402 /* 403 * Callback routine for when a transport is closed. 404 */ 405 static void 406 rdcsrv_xprtclose(const SVCXPRT *xprt) 407 { 408 } 409 #endif 410 411 412 /* 413 * Private interface from the main RDC module. 414 */ 415 416 int 417 rdcsrv_load(file_t *fp, rdcsrv_t *disptab, rdc_svc_args_t *args, int mode) 418 { 419 int rc = 0; 420 421 mutex_enter(&rdcsrv_lock); 422 423 rc = rdcsrv_create(fp, args, mode); 424 if (rc == 0) { 425 rdcsrv_disptab = disptab; 426 } 427 428 mutex_exit(&rdcsrv_lock); 429 return (rc); 430 } 431 432 433 void 434 rdcsrv_unload(void) 435 { 436 mutex_enter(&rdcsrv_lock); 437 438 /* Unset rdcstub's dispatch handle */ 439 rdcstub_unset_dispatch(); 440 441 rdcsrv_closing = 1; 442 443 while (rdcsrv_refcnt > 0) { 444 mutex_exit(&rdcsrv_lock); 445 delay(drv_usectohz(25)); 446 mutex_enter(&rdcsrv_lock); 447 } 448 449 rdcsrv_closing = 0; 450 rdcsrv_disptab = 0; 451 452 mutex_exit(&rdcsrv_lock); 453 } 454