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, 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, "!rdcsrv_dispatch: unknown version %d", 229 req->rq_vers); 230 /* svcerr_noproc does a freeargs on xprt */ 231 goto done; 232 } 233 234 srvp = &rdcsrv_disptab[req->rq_vers - RDC_VERS_MIN]; 235 disp = &srvp->disptab[req->rq_proc]; 236 237 if (req->rq_proc >= srvp->nprocs || 238 disp->dispfn == rdcsrv_noproc) { 239 svcerr_noproc(xprt); 240 cmn_err(CE_NOTE, "!rdcsrv_dispatch: bad proc number %d", 241 req->rq_proc); 242 /* svcerr_noproc does a freeargs on xprt */ 243 goto done; 244 } else if (disp->clone) { 245 switch (rdcsrv_dispdup(req, xprt)) { 246 case DUP_ERROR: 247 goto done; 248 /* NOTREACHED */ 249 case DUP_INPROGRESS: 250 goto outdisp; 251 /* NOTREACHED */ 252 default: 253 break; 254 } 255 } else { 256 (*disp->dispfn)(xprt, req); 257 rdc_svc_count++; 258 } 259 260 outdisp: 261 if (!SVC_FREEARGS(xprt, (xdrproc_t)0, (caddr_t)0)) 262 cmn_err(CE_NOTE, "!rdcsrv_dispatch: bad freeargs"); 263 done: 264 mutex_enter(&rdcsrv_lock); 265 rdcsrv_refcnt--; 266 mutex_exit(&rdcsrv_lock); 267 } 268 269 270 static int 271 rdcsrv_create(file_t *fp, rdc_svc_args_t *args, int mode) 272 { 273 /*LINTED*/ 274 int rc, error = 0; 275 /*LINTED*/ 276 rpcvers_t vers; 277 struct netbuf addrmask; 278 279 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 280 SVCXPRT *xprt; 281 #else 282 SVCMASTERXPRT *xprt; 283 #endif 284 STRUCT_HANDLE(rdc_svc_args, uap); 285 286 STRUCT_SET_HANDLE(uap, mode, args); 287 288 addrmask.len = STRUCT_FGET(uap, addrmask.len); 289 addrmask.maxlen = STRUCT_FGET(uap, addrmask.maxlen); 290 addrmask.buf = kmem_alloc(addrmask.maxlen, KM_SLEEP); 291 error = ddi_copyin(STRUCT_FGETP(uap, addrmask.buf), addrmask.buf, 292 addrmask.len, mode); 293 if (error) { 294 kmem_free(addrmask.buf, addrmask.maxlen); 295 #ifdef DEBUG 296 cmn_err(CE_WARN, "!addrmask copyin failed %p", (void *) args); 297 #endif 298 return (error); 299 } 300 301 /* 302 * Set rdcstub's dispatch handle to rdcsrv_dispatch 303 */ 304 rdcstub_set_dispatch(rdcsrv_dispatch); 305 306 /* 307 * Create a transport endpoint and create one kernel thread to run the 308 * rdc service loop 309 */ 310 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 311 error = svc_tli_kcreate(fp, RDC_RPC_MAX, 312 STRUCT_FGETP(uap, netid), &addrmask, STRUCT_FGET(uap, nthr), &xprt); 313 #else 314 { 315 #if defined(_SunOS_5_8) 316 struct svcpool_args p; 317 p.id = RDC_SVCPOOL_ID; 318 p.maxthreads = STRUCT_FGET(uap, nthr); 319 p.redline = 0; 320 p.qsize = 0; 321 p.timeout = 0; 322 p.stksize = 0; 323 p.max_same_xprt = 0; 324 325 error = svc_pool_create(&p); 326 if (error) { 327 cmn_err(CE_NOTE, 328 "!rdcsrv_create: svc_pool_create failed %d", error); 329 return (error); 330 } 331 #endif 332 error = svc_tli_kcreate(fp, RDC_RPC_MAX, 333 STRUCT_FGETP(uap, netid), &addrmask, 334 &xprt, &rdcsrv_sct, NULL, RDC_SVCPOOL_ID, FALSE); 335 } 336 #endif 337 338 if (error) { 339 cmn_err(CE_NOTE, "!rdcsrv_create: svc_tli_kcreate failed %d", 340 error); 341 return (error); 342 } 343 344 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 345 if (xprt == NULL) { 346 cmn_err(CE_NOTE, "!xprt in rdcsrv_create is NULL"); 347 } else { 348 /* 349 * Register a cleanup routine in case the transport gets 350 * destroyed. If the registration fails for some reason, 351 * it means that the transport is already being destroyed. 352 * This shouldn't happen, but it's probably not worth a 353 * panic. 354 */ 355 if (!svc_control(xprt, SVCSET_CLOSEPROC, 356 (void *)rdcsrv_xprtclose)) { 357 cmn_err( 358 #ifdef DEBUG 359 CE_PANIC, 360 #else 361 CE_WARN, 362 #endif 363 "!rdcsrv_create: couldn't set xprt callback"); 364 365 error = EBADF; 366 goto done; 367 } 368 } 369 370 for (vers = RDC_VERS_MIN; vers <= RDC_VERS_MAX; vers++) { 371 rc = svc_register(xprt, (ulong_t)RDC_PROGRAM, vers, 372 rdcstub_dispatch, 0); 373 if (!rc) { 374 cmn_err(CE_NOTE, 375 "!rdcsrv_create: svc_register(%d, %lu) failed", 376 RDC_PROGRAM, vers); 377 378 if (!error) { 379 error = EBADF; 380 } 381 } 382 } 383 #endif /* 5.6 or 5.7 */ 384 385 if (!error) { 386 /* mark as registered with the kRPC subsystem */ 387 rdcsrv_registered = 1; 388 } 389 390 done: 391 return (error); 392 } 393 394 395 #if defined(_SunOS_5_6) || defined(_SunOS_5_7) 396 /* 397 * Callback routine for when a transport is closed. 398 */ 399 static void 400 rdcsrv_xprtclose(const SVCXPRT *xprt) 401 { 402 } 403 #endif 404 405 406 /* 407 * Private interface from the main RDC module. 408 */ 409 410 int 411 rdcsrv_load(file_t *fp, rdcsrv_t *disptab, rdc_svc_args_t *args, int mode) 412 { 413 int rc = 0; 414 415 mutex_enter(&rdcsrv_lock); 416 417 rc = rdcsrv_create(fp, args, mode); 418 if (rc == 0) { 419 rdcsrv_disptab = disptab; 420 } 421 422 mutex_exit(&rdcsrv_lock); 423 return (rc); 424 } 425 426 427 void 428 rdcsrv_unload(void) 429 { 430 mutex_enter(&rdcsrv_lock); 431 432 /* Unset rdcstub's dispatch handle */ 433 rdcstub_unset_dispatch(); 434 435 rdcsrv_closing = 1; 436 437 while (rdcsrv_refcnt > 0) { 438 mutex_exit(&rdcsrv_lock); 439 delay(drv_usectohz(25)); 440 mutex_enter(&rdcsrv_lock); 441 } 442 443 rdcsrv_closing = 0; 444 rdcsrv_disptab = 0; 445 446 mutex_exit(&rdcsrv_lock); 447 }