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 2009 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, NULL } 119 }; 120 121 122 int 123 _init(void) 124 { 125 int rc; 126 127 mutex_init(&rdcsrv_lock, NULL, MUTEX_DRIVER, NULL); 128 129 if ((rc = mod_install(&modlinkage)) != DDI_SUCCESS) 130 mutex_destroy(&rdcsrv_lock); 131 132 return (rc); 133 } 134 135 136 int 137 _fini(void) 138 { 139 int rc; 140 141 if ((rc = mod_remove(&modlinkage)) == DDI_SUCCESS) 142 mutex_destroy(&rdcsrv_lock); 143 144 return (rc); 145 } 146 147 148 int 149 _info(struct modinfo *modinfop) 150 { 151 return (mod_info(&modlinkage, modinfop)); 152 } 153 154 155 /* 156 * RDC kRPC server stub. 157 */ 158 159 void 160 rdcsrv_noproc(void) 161 { 162 ; 163 } 164 165 166 static int 167 rdcsrv_dispdup(struct svc_req *req, SVCXPRT *xprt) 168 { 169 rdc_disptab_t *disp; 170 struct dupreq *dr; 171 rdcsrv_t *srvp; 172 void (*fn)(); 173 int dupstat; 174 175 srvp = &rdcsrv_disptab[req->rq_vers - RDC_VERS_MIN]; 176 disp = &srvp->disptab[req->rq_proc]; 177 fn = disp->dispfn; 178 179 dupstat = SVC_DUP(xprt, req, 0, 0, &dr); 180 181 switch (dupstat) { 182 case DUP_ERROR: 183 /* svcerr_systemerr does a freeargs */ 184 svcerr_systemerr(xprt); 185 rdcsrv_dup_error++; 186 break; 187 188 case DUP_INPROGRESS: 189 rdcsrv_dup_error++; 190 break; 191 192 case DUP_NEW: 193 case DUP_DROP: 194 (*fn)(xprt, req); 195 SVC_DUPDONE(xprt, dr, 0, 0, DUP_DONE); 196 break; 197 198 case DUP_DONE: 199 break; 200 } 201 202 return (dupstat); 203 } 204 205 206 /* 207 * rdcsrv_dispatch is the dispatcher routine for the RDC RPC protocol 208 */ 209 void 210 rdcsrv_dispatch(struct svc_req *req, SVCXPRT *xprt) 211 { 212 rdc_disptab_t *disp; 213 rdcsrv_t *srvp; 214 215 mutex_enter(&rdcsrv_lock); 216 rdcsrv_refcnt++; 217 218 if (!rdcsrv_registered || rdcsrv_closing || !rdcsrv_disptab) { 219 mutex_exit(&rdcsrv_lock); 220 goto outdisp; 221 } 222 223 mutex_exit(&rdcsrv_lock); 224 225 if ((req->rq_vers < RDC_VERS_MIN) || (req->rq_vers > RDC_VERS_MAX)) { 226 svcerr_noproc(xprt); 227 cmn_err(CE_NOTE, "!rdcsrv_dispatch: unknown version %d", 228 req->rq_vers); 229 /* svcerr_noproc does a freeargs on xprt */ 230 goto done; 231 } 232 233 srvp = &rdcsrv_disptab[req->rq_vers - RDC_VERS_MIN]; 234 disp = &srvp->disptab[req->rq_proc]; 235 236 if (req->rq_proc >= srvp->nprocs || 237 disp->dispfn == rdcsrv_noproc) { 238 svcerr_noproc(xprt); 239 cmn_err(CE_NOTE, "!rdcsrv_dispatch: bad proc number %d", 240 req->rq_proc); 241 /* svcerr_noproc does a freeargs on xprt */ 242 goto done; 243 } else if (disp->clone) { 244 switch (rdcsrv_dispdup(req, xprt)) { 245 case DUP_ERROR: 246 goto done; 247 /* NOTREACHED */ 248 case DUP_INPROGRESS: 249 goto outdisp; 250 /* NOTREACHED */ 251 default: 252 break; 253 } 254 } else { 255 (*disp->dispfn)(xprt, req); 256 rdc_svc_count++; 257 } 258 259 outdisp: 260 if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) 261 cmn_err(CE_NOTE, "!rdcsrv_dispatch: bad freeargs"); 262 done: 263 mutex_enter(&rdcsrv_lock); 264 rdcsrv_refcnt--; 265 mutex_exit(&rdcsrv_lock); 266 } 267 268 269 static int 270 rdcsrv_create(file_t *fp, rdc_svc_args_t *args, int mode) 271 { 272 /*LINTED*/ 273 int rc, error = 0; 274 /*LINTED*/ 275 rpcvers_t vers; 276 struct netbuf addrmask; 277 278 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 279 SVCXPRT *xprt; 280 #else 281 SVCMASTERXPRT *xprt; 282 #endif 283 STRUCT_HANDLE(rdc_svc_args, uap); 284 285 STRUCT_SET_HANDLE(uap, mode, args); 286 287 addrmask.len = STRUCT_FGET(uap, addrmask.len); 288 addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen); 289 addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP); 290 error = ddi_copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf, 291 addrmask.len, mode); 292 if (error) { 293 kmem_free(addrmask.buf, addrmask.maxlen); 294 #ifdef DEBUG 295 cmn_err(CE_WARN, "!addrmask copyin failed %p", (void *) args); 296 #endif 297 return (error); 298 } 299 300 /* 301 * Set rdcstub's dispatch handle to rdcsrv_dispatch 302 */ 303 rdcstub_set_dispatch(rdcsrv_dispatch); 304 305 /* 306 * Create a transport endpoint and create one kernel thread to run the 307 * rdc service loop 308 */ 309 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 310 error = svc_tli_kcreate(fp, RDC_RPC_MAX, 311 STRUCT_FGETP(uap, netid), &addrmask, STRUCT_FGET(uap, nthr), &xprt); 312 #else 313 { 314 #if defined(_SunOS_5_8) 315 struct svcpool_args p; 316 p.id = RDC_SVCPOOL_ID; 317 p.maxthreads = STRUCT_FGET(uap, nthr); 318 p.redline = 0; 319 p.qsize = 0; 320 p.timeout = 0; 321 p.stksize = 0; 322 p.max_same_xprt = 0; 323 324 error = svc_pool_create(&p); 325 if (error) { 326 cmn_err(CE_NOTE, 327 "!rdcsrv_create: svc_pool_create failed %d", error); 328 return (error); 329 } 330 #endif 331 error = svc_tli_kcreate(fp, RDC_RPC_MAX, 332 STRUCT_FGETP(uap, netid), &addrmask, 333 &xprt, &rdcsrv_sct, NULL, RDC_SVCPOOL_ID, FALSE); 334 } 335 #endif 336 337 if (error) { 338 cmn_err(CE_NOTE, "!rdcsrv_create: svc_tli_kcreate failed %d", 339 error); 340 return (error); 341 } 342 343 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 344 if (xprt == NULL) { 345 cmn_err(CE_NOTE, "!xprt in rdcsrv_create is NULL"); 346 } else { 347 /* 348 * Register a cleanup routine in case the transport gets 349 * destroyed. If the registration fails for some reason, 350 * it means that the transport is already being destroyed. 351 * This shouldn't happen, but it's probably not worth a 352 * panic. 353 */ 354 if (!svc_control(xprt, SVCSET_CLOSEPROC, 355 (void *)rdcsrv_xprtclose)) { 356 cmn_err( 357 #ifdef DEBUG 358 CE_PANIC, 359 #else 360 CE_WARN, 361 #endif 362 "!rdcsrv_create: couldn't set xprt callback"); 363 364 error = EBADF; 365 goto done; 366 } 367 } 368 369 for (vers = RDC_VERS_MIN; vers <= RDC_VERS_MAX; vers++) { 370 rc = svc_register(xprt, (ulong_t)RDC_PROGRAM, vers, 371 rdcstub_dispatch, 0); 372 if (!rc) { 373 cmn_err(CE_NOTE, 374 "!rdcsrv_create: svc_register(%d, %lu) failed", 375 RDC_PROGRAM, vers); 376 377 if (!error) { 378 error = EBADF; 379 } 380 } 381 } 382 #endif /* 5.6 or 5.7 */ 383 384 if (!error) { 385 /* mark as registered with the kRPC subsystem */ 386 rdcsrv_registered = 1; 387 } 388 389 done: 390 return (error); 391 } 392 393 394 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 395 /* 396 * Callback routine for when a transport is closed. 397 */ 398 static void 399 rdcsrv_xprtclose(const SVCXPRT *xprt) 400 { 401 } 402 #endif 403 404 405 /* 406 * Private interface from the main RDC module. 407 */ 408 409 int 410 rdcsrv_load(file_t *fp, rdcsrv_t *disptab, rdc_svc_args_t *args, int mode) 411 { 412 int rc = 0; 413 414 mutex_enter(&rdcsrv_lock); 415 416 rc = rdcsrv_create(fp, args, mode); 417 if (rc == 0) { 418 rdcsrv_disptab = disptab; 419 } 420 421 mutex_exit(&rdcsrv_lock); 422 return (rc); 423 } 424 425 426 void 427 rdcsrv_unload(void) 428 { 429 mutex_enter(&rdcsrv_lock); 430 431 /* Unset rdcstub's dispatch handle */ 432 rdcstub_unset_dispatch(); 433 434 rdcsrv_closing = 1; 435 436 while (rdcsrv_refcnt > 0) { 437 mutex_exit(&rdcsrv_lock); 438 delay(drv_usectohz(25)); 439 mutex_enter(&rdcsrv_lock); 440 } 441 442 rdcsrv_closing = 0; 443 rdcsrv_disptab = 0; 444 445 mutex_exit(&rdcsrv_lock); 446 }