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/param.h>
27 #include <sys/systm.h>
28 #include <sys/sysmacros.h>
29 #include <sys/errno.h>
30 #include <sys/cmn_err.h>
31 #include <sys/buf.h>
32 #include <sys/disp.h>
33 #include <sys/kmem.h>
34 /* #include <sys/ddi.h> */
35 /* #include <sys/sunddi.h> */
36 #include <sys/debug.h>
37
38 #include <sys/time.h>
39 #include <sys/pathname.h>
40 #include <sys/netconfig.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43
44 #include <rpc/types.h>
45 #include <rpc/auth.h>
46 #include <rpc/clnt.h>
47 #include <rpc/clnt_soc.h>
48 #include <rpc/pmap_prot.h> /* PMAPPORT */
49 #include <rpc/rpc.h>
50 #include <rpc/rpcb_prot.h>
51 #include <rpc/xdr.h> /* This also gets us htonl() et al. */
52
53
54 #include <sys/lvm/mdmed.h>
55
56 #define MDDB
57 #include <sys/lvm/mdvar.h>
58 #include <sys/lvm/md_mddb.h>
59 #include <sys/lvm/md_crc.h>
60 #include <sys/callb.h>
61
62 /*
63 * Flag to turn off the kernel RPC client delay code. This only takes effect
64 * if the route to the remote node is marked as RTF_REJECT and the RPC path
65 * manager has been flushed such that any 'old' path information is no longer
66 * present.
67 */
68 static bool_t clset = TRUE;
69
70 extern int md_nmedh; /* declared in md.c */
71 extern char *md_med_trans_lst;
72 extern md_set_t md_set[]; /* declared in md.c */
73
74 /*
75 * Structures used only by mediators
76 */
77 typedef struct med_thr_a_args {
78 uint_t mtaa_mag;
79 char *mtaa_h_nm;
80 in_addr_t mtaa_h_ip;
81 uint_t mtaa_h_flags;
82 int (*mtaa_err_func)(struct med_thr_a_args *);
83 struct med_thr_h_args *mtaa_mthap;
84 int mtaa_flags;
85 rpcprog_t mtaa_prog;
86 rpcvers_t mtaa_vers;
87 rpcproc_t mtaa_proc;
88 xdrproc_t mtaa_inproc;
89 caddr_t mtaa_in;
90 xdrproc_t mtaa_outproc;
91 caddr_t mtaa_out;
92 struct timeval *mtaa_timout;
93 int mtaa_err;
94 } med_thr_a_args_t;
95
96 #define MTAA_MAGIC 0xbadbabed
97 #define MDT_A_OK 0x00000001
98
99 typedef struct med_thr_h_args {
100 uint_t mtha_mag;
101 md_hi_t *mtha_mhp;
102 char *mtha_setname;
103 med_data_t *mtha_meddp;
104 struct med_thr *mtha_mtp;
105 int mtha_flags;
106 set_t mtha_setno;
107 int mtha_a_cnt;
108 kcondvar_t mtha_a_cv;
109 kmutex_t mtha_a_mx;
110 uint_t mtha_a_nthr;
111 med_thr_a_args_t mtha_a_args[MAX_HOST_ADDRS];
112 } med_thr_h_args_t;
113
114 #define MTHA_MAGIC 0xbadbabee
115 #define MDT_H_OK 0x00000001
116
117 typedef struct med_thr {
118 uint_t mt_mag;
119 kmutex_t mt_mx;
120 kcondvar_t mt_cv;
121 uint_t mt_nthr;
122 med_thr_h_args_t *mt_h_args[MED_MAX_HOSTS];
123 } med_thr_t;
124
125 #define MTH_MAGIC 0xbadbabef
126
127 #ifdef DEBUG
128
129 static struct timeval btv;
130 static struct timeval etv;
131
132 #define DBGLVL_NONE 0x00000000
133 #define DBGLVL_MAJOR 0x00000100
134 #define DBGLVL_MINOR 0x00000200
135 #define DBGLVL_MINUTE 0x00000400
136 #define DBGLVL_TRIVIA 0x00000800
137 #define DBGLVL_HIDEOUS 0x00001000
138
139 #define DBGFLG_NONE 0x00000000
140 #define DBGFLG_NOPANIC 0x00000001
141 #define DBGFLG_LVLONLY 0x00000002
142 #define DBGFLG_FIXWOULDPANIC 0x00000004
143
144 #define DBGFLG_FLAGMASK 0x0000000F
145 #define DBGFLG_LEVELMASK ~DBGFLG_FLAGMASK
146
147 #define DEBUG_FLAGS (md_medup_failure_dbg & DBGFLG_FLAGMASK)
148 #define DEBUG_LEVEL (md_medup_failure_dbg & DBGFLG_LEVELMASK)
149
150 #ifdef JEC
151 unsigned int md_medup_failure_dbg = DBGLVL_MINOR | DBGFLG_NONE;
152 #else /* ! JEC */
153 unsigned int md_medup_failure_dbg = DBGLVL_NONE | DBGFLG_NONE;
154 #endif /* JEC */
155
156 #define DCALL(dbg_level, call) \
157 { \
158 if (DEBUG_LEVEL != DBGLVL_NONE) { \
159 if (DEBUG_FLAGS & DBGFLG_LVLONLY) { \
160 if (DEBUG_LEVEL & dbg_level) { \
161 call; \
162 } \
163 } else { \
164 if (dbg_level <= DEBUG_LEVEL) { \
165 call; \
166 } \
167 } \
168 } \
169 }
170
171 #define DPRINTF(dbg_level, msg) DCALL(dbg_level, printf msg)
172
173 #define MAJOR(msg) DPRINTF(DBGLVL_MAJOR, msg)
174 #define MINOR(msg) DPRINTF(DBGLVL_MINOR, msg)
175 #define MINUTE(msg) DPRINTF(DBGLVL_MINUTE, msg)
176 #define TRIVIA(msg) DPRINTF(DBGLVL_TRIVIA, msg)
177 #define HIDEOUS(msg) DPRINTF(DBGLVL_HIDEOUS, msg)
178 #define BSTAMP { uniqtime(&btv); }
179
180 #define ESTAMP(msg) \
181 { \
182 time_t esec, eusec; \
183 \
184 uniqtime(&etv); \
185 \
186 eusec = etv.tv_usec - btv.tv_usec; \
187 esec = etv.tv_sec - btv.tv_sec; \
188 if (eusec < 0) { \
189 eusec += MICROSEC; \
190 esec--; \
191 } \
192 MINOR(("%s: sec=%ld, usec=%ld\n", msg, esec, eusec)); \
193 }
194
195 #else /* ! DEBUG */
196
197 #define DCALL(ignored_dbg_level, ignored_routine)
198 #define MAJOR(ignored)
199 #define MINOR(ignored)
200 #define MINUTE(ignored)
201 #define TRIVIA(ignored)
202 #define HIDEOUS(ignored)
203 #define BSTAMP { }
204 #define ESTAMP(msg) { }
205
206 #endif /* DEBUG */
207
208 static int md_med_protocol_retry = 2;
209 static int md_med_transdevs_set = 0;
210
211 /*
212 * Definitions and declarations.
213 */
214 kmutex_t med_lck;
215
216 struct med_client {
217 rpcprog_t prog;
218 rpcvers_t vers;
219 struct netbuf addr; /* Address to this <prog,vers> */
220 CLIENT *client;
221 };
222
223 /*
224 * unrecoverable RPC status codes; cf. rfscall()
225 */
226 #define MED_IS_UNRECOVERABLE_RPC(s) (((s) == RPC_AUTHERROR) || \
227 ((s) == RPC_CANTENCODEARGS) || \
228 ((s) == RPC_CANTDECODERES) || \
229 ((s) == RPC_VERSMISMATCH) || \
230 ((s) == RPC_PROCUNAVAIL) || \
231 ((s) == RPC_PROGUNAVAIL) || \
232 ((s) == RPC_PROGVERSMISMATCH) || \
233 ((s) == RPC_CANTDECODEARGS))
234
235 /*
236 * When trying to contact a portmapper that doesn't speak the version we're
237 * using, we should theoretically get back RPC_PROGVERSMISMATCH.
238 * Unfortunately, some (all?) 4.x hosts return an accept_stat of
239 * PROG_UNAVAIL, which gets mapped to RPC_PROGUNAVAIL, so we have to check
240 * for that, too.
241 */
242 #define PMAP_WRONG_VERSION(s) ((s) == RPC_PROGVERSMISMATCH || \
243 (s) == RPC_PROGUNAVAIL)
244
245 #define NULLSTR(str) (! (str) || *(str) == '\0'? "<null>" : (str))
246 #define NULSTRING ""
247
248 /* Flags used in med_addr (netconfig) table */
249
250 #define UAFLG_NONE 0x00000000
251 #define UAFLG_SKIP 0x00000001
252 #define UAFLG_ERROR 0x00000002
253 #define UAFLG_RPCERROR 0x00000004
254 #define UAFLG_LOOPBACK 0x00000008
255 #define UAFLG_LOCKINIT 0x00000010
256
257 /*
258 * most of this data is static. The mutex protects the changable items:
259 * ua_flags
260 */
261 static struct med_addr {
262 struct knetconfig ua_kn;
263 char *ua_devname; /* const */
264 char *ua_netid; /* const */
265 uint_t ua_flags;
266 kmutex_t ua_mutex;
267 } med_addr_tab[] =
268
269 /*
270 * The order of the entries in this table is the order in
271 * which we'll try to connect to the user-level daemon.
272 * The final entry must have a NULL ua_devname.
273 *
274 * This is basically a tablified version of /etc/netconfig
275 * (with additional entries for loopback TCP and UDP networks
276 * that are missing from the user-level version.)
277 */
278 {
279
280 /* loopback UDP */
281 /* semantics protofmly proto, dev_t */
282 { { NC_TPI_CLTS, NC_INET, NC_UDP, NODEV },
283 /* devname netid flags */
284 "/dev/udp", "udp-loopback", UAFLG_LOOPBACK
285 },
286
287 /* UDP */
288 /* semantics protofmly proto, dev_t */
289 { { NC_TPI_CLTS, NC_INET, NC_UDP, NODEV },
290 /* devname netid flags */
291 "/dev/udp", "udp", UAFLG_NONE
292 },
293
294 /* loopback TCP */
295 /* semantics protofmly proto, dev_t */
296 { { NC_TPI_COTS_ORD, NC_INET, NC_TCP, NODEV },
297 /* devname netid flags */
298 "/dev/tcp", "tcp-loopback", UAFLG_LOOPBACK
299 },
300
301 /* TCP */
302 /* semantics protofmly proto, dev_t */
303 { { NC_TPI_COTS_ORD, NC_INET, NC_TCP, NODEV },
304 /* devname netid flags */
305 "/dev/tcp", "tcp", UAFLG_NONE
306 },
307
308 /* ticlts */
309 /* semantics protofmly proto, dev_t */
310 { { NC_TPI_CLTS, NC_LOOPBACK, NC_NOPROTO, NODEV },
311 /* devname netid flags */
312 "/dev/ticlts", "ticlts", UAFLG_LOOPBACK
313 },
314
315 /* ticotsord */
316 /* semantics protofmly proto, dev_t */
317 { { NC_TPI_COTS_ORD, NC_LOOPBACK, NC_NOPROTO, NODEV },
318 /* devname netid flags */
319 "/dev/ticotsord", "ticotsord", UAFLG_LOOPBACK
320 },
321
322 /* ticots */
323 /* semantics protofmly proto, dev_t */
324 { { NC_TPI_COTS, NC_LOOPBACK, NC_NOPROTO, NODEV },
325 /* devname netid flags */
326 "/dev/ticots", "ticots", UAFLG_LOOPBACK
327 }
328 };
329
330 /* The number of entries in the table */
331 int med_addr_tab_nents = sizeof (med_addr_tab) / sizeof (med_addr_tab[0]);
332
333 /*
334 * Private Functions
335 */
336
337 /* A useful utility. */
338 static char *
med_dup(void * str,int len)339 med_dup(void *str, int len)
340 {
341 char *s = (char *)kmem_zalloc(len, KM_SLEEP);
342
343 if (s == NULL)
344 return (NULL);
345
346 bcopy(str, s, len);
347
348 return (s);
349 }
350
351 /*
352 * Utilities for manipulating netbuf's.
353 * These utilities are the only knc_protofmly specific functions in the MED.
354 */
355
356 /*
357 * Utilities to patch a port number (for NC_INET protocols) or a
358 * port name (for NC_LOOPBACK) into a network address.
359 */
360 static void
med_put_inet_port(struct netbuf * addr,ushort_t port)361 med_put_inet_port(struct netbuf *addr, ushort_t port)
362 {
363 /*
364 * Easy - we always patch an unsigned short on top of an
365 * unsigned short. No changes to addr's len or maxlen are
366 * necessary.
367 */
368 /*LINTED*/
369 ((struct sockaddr_in *)(addr->buf))->sin_port = port;
370 }
371
372 static void
med_put_loopback_port(struct netbuf * addr,char * port)373 med_put_loopback_port(struct netbuf *addr, char *port)
374 {
375 char *dot;
376 char *newbuf;
377 int newlen;
378
379 /*
380 * We must make sure the addr has enough space for us,
381 * patch in `port', and then adjust addr's len and maxlen
382 * to reflect the change.
383 */
384 if ((dot = strchr(addr->buf, '.')) == (char *)NULL) {
385 TRIVIA(("put_loopb_port - malformed loopback addr %s\n",
386 addr->buf));
387 return;
388 }
389
390 newlen = (int)((dot - addr->buf + 1) + strlen(port));
391 if (newlen > addr->maxlen) {
392 newbuf = (char *)kmem_zalloc((size_t)newlen, KM_SLEEP);
393 (void) bcopy(addr->buf, newbuf, (size_t)addr->len);
394 kmem_free(addr->buf, (size_t)addr->maxlen);
395 addr->buf = newbuf;
396 addr->len = addr->maxlen = (uint_t)newlen;
397 dot = strchr(addr->buf, '.');
398 } else {
399 addr->len = newlen;
400 }
401
402 (void) strncpy(++dot, port, strlen(port));
403
404 }
405
406 /*
407 * Make sure the given netbuf has a maxlen at least as big as the given
408 * length.
409 */
410 static void
grow_netbuf(struct netbuf * nb,size_t length)411 grow_netbuf(struct netbuf *nb, size_t length)
412 {
413 char *newbuf;
414
415 if (nb->maxlen >= length)
416 return;
417
418 newbuf = kmem_zalloc(length, KM_SLEEP);
419 bcopy(nb->buf, newbuf, (size_t)nb->len);
420 kmem_free(nb->buf, (size_t)nb->maxlen);
421 nb->buf = newbuf;
422 nb->maxlen = (uint_t)length;
423 }
424
425 /*
426 * Convert a loopback universal address to a loopback transport address.
427 */
428 static void
loopb_u2t(const char * ua,struct netbuf * addr)429 loopb_u2t(const char *ua, struct netbuf *addr)
430 {
431 size_t stringlen = strlen(ua) + 1;
432 const char *univp; /* ptr into universal addr */
433 char *transp; /* ptr into transport addr */
434
435 /* Make sure the netbuf will be big enough. */
436 if (addr->maxlen < stringlen) {
437 grow_netbuf(addr, stringlen);
438 }
439
440 univp = ua;
441 transp = addr->buf;
442 while (*univp != NULL) {
443 if (*univp == '\\' && *(univp+1) == '\\') {
444 *transp = '\\';
445 univp += 2;
446 } else if (*univp == '\\') {
447 /* octal character */
448 *transp = (((*(univp+1) - '0') & 3) << 6) +
449 (((*(univp+2) - '0') & 7) << 3) +
450 ((*(univp+3) - '0') & 7);
451 univp += 4;
452 } else {
453 *transp = *univp;
454 univp++;
455 }
456 transp++;
457 }
458
459 addr->len = (uint_t)(transp - addr->buf);
460 ASSERT(addr->len <= addr->maxlen);
461 }
462
463
464 /*
465 * xdr_md_pmap
466 *
467 * Taken from libnsl/rpc/pmap_prot.c
468 */
469 bool_t
xdr_md_pmap(xdrs,regs)470 xdr_md_pmap(xdrs, regs)
471 XDR *xdrs;
472 struct pmap *regs;
473 {
474 if (xdr_u_int(xdrs, ®s->pm_prog) &&
475 xdr_u_int(xdrs, ®s->pm_vers) &&
476 xdr_u_int(xdrs, ®s->pm_prot))
477 return (xdr_u_int(xdrs, ®s->pm_port));
478 return (FALSE);
479 }
480
481 /*
482 * We need an version of CLNT_DESTROY which also frees the auth structure.
483 */
484 static void
med_clnt_destroy(CLIENT ** clp)485 med_clnt_destroy(CLIENT **clp)
486 {
487 if (*clp) {
488 if ((*clp)->cl_auth) {
489 AUTH_DESTROY((*clp)->cl_auth);
490 (*clp)->cl_auth = NULL;
491 }
492 CLNT_DESTROY(*clp);
493 *clp = NULL;
494 }
495 }
496
497 /*
498 * Release this med_client entry.
499 * Do also destroy the entry if there was an error != EINTR,
500 * and mark the entry as not-valid, by setting time=0.
501 */
502 static void
med_rel_client(struct med_client * medc,int error)503 med_rel_client(struct med_client *medc, int error)
504 {
505 TRIVIA(("rel_client - addr = (%p, %u %u)\n",
506 (void *) medc->addr.buf, medc->addr.len, medc->addr.maxlen));
507 /*LINTED*/
508 if (1 || error && error != EINTR) {
509 TRIVIA(("rel_client - destroying addr = (%p, %u %u)\n",
510 (void *) medc->addr.buf, medc->addr.len,
511 medc->addr.maxlen));
512 med_clnt_destroy(&medc->client);
513 if (medc->addr.buf) {
514 kmem_free(medc->addr.buf, medc->addr.maxlen);
515 medc->addr.buf = NULL;
516 }
517 }
518 }
519
520 /*
521 * Try to get the address for the desired service by using the old
522 * portmapper protocol. Ignores signals.
523 *
524 * Returns RPC_UNKNOWNPROTO if the request uses the loopback transport.
525 * Use med_get_rpcb_addr instead.
526 */
527 static enum clnt_stat
med_get_pmap_addr(struct knetconfig * kncfp,rpcprog_t prog,rpcvers_t vers,struct netbuf * addr)528 med_get_pmap_addr(
529 struct knetconfig *kncfp,
530 rpcprog_t prog,
531 rpcvers_t vers,
532 struct netbuf *addr
533 )
534 {
535 ushort_t port = 0;
536 int error;
537 enum clnt_stat status;
538 CLIENT *client = NULL;
539 struct pmap parms;
540 struct timeval tmo;
541 k_sigset_t oldmask;
542 k_sigset_t newmask;
543
544 /*
545 * Call rpcbind version 2 or earlier (SunOS portmapper, remote
546 * only) to get an address we can use in an RPC client handle.
547 * We simply obtain a port no. for <prog, vers> and plug it
548 * into `addr'.
549 */
550 if (strcmp(kncfp->knc_protofmly, NC_INET) == 0) {
551 med_put_inet_port(addr, htons(PMAPPORT));
552 } else {
553 TRIVIA(("get_pmap_addr - unsupported protofmly %s\n",
554 kncfp->knc_protofmly));
555 status = RPC_UNKNOWNPROTO;
556 goto out;
557 }
558
559 TRIVIA(("get_pmap_addr - semantics=%u, protofmly=%s, proto=%s\n",
560 kncfp->knc_semantics, kncfp->knc_protofmly, kncfp->knc_proto));
561
562 /*
563 * Mask signals for the duration of the handle creation and
564 * RPC call. This allows relatively normal operation with a
565 * signal already posted to our thread.
566 *
567 * Any further exit paths from this routine must restore
568 * the original signal mask.
569 */
570 sigfillset(&newmask);
571 sigreplace(&newmask, &oldmask);
572
573 if ((error = clnt_tli_kcreate(kncfp, addr, PMAPPROG, PMAPVERS,
574 0, 0, kcred, &client)) != RPC_SUCCESS) {
575 status = RPC_TLIERROR;
576 sigreplace(&oldmask, (k_sigset_t *)NULL);
577 MINUTE(("get_pmap_addr - kcreate() returned %d\n", error));
578 goto out;
579 }
580
581 if (!CLNT_CONTROL(client, CLSET_NODELAYONERR, (char *)&clset)) {
582 MINUTE(("get_pmap_addr - unable to set CLSET_NODELAYONERR\n"));
583 }
584
585 client->cl_auth = authkern_create();
586
587 parms.pm_prog = prog;
588 parms.pm_vers = vers;
589 if (strcmp(kncfp->knc_proto, NC_TCP) == 0) {
590 parms.pm_prot = IPPROTO_TCP;
591 } else {
592 parms.pm_prot = IPPROTO_UDP;
593 }
594 parms.pm_port = 0;
595 tmo = md_med_pmap_timeout;
596
597 if ((status = CLNT_CALL(client, PMAPPROC_GETPORT,
598 xdr_md_pmap, (char *)&parms,
599 xdr_u_short, (char *)&port,
600 tmo)) != RPC_SUCCESS) {
601 sigreplace(&oldmask, (k_sigset_t *)NULL);
602 MINUTE(("get_pmap_addr - CLNT_CALL(GETPORT) returned %d\n",
603 status));
604 goto out;
605 }
606
607 sigreplace(&oldmask, (k_sigset_t *)NULL);
608
609 /* A zero value of port indicates a mapping failure */
610 if (port == 0) {
611 status = RPC_PROGNOTREGISTERED;
612 MINUTE(("get_pmap_addr - program not registered\n"));
613 goto out;
614 }
615
616 TRIVIA(("get_pmap_addr - port=%d\n", port));
617 med_put_inet_port(addr, ntohs(port));
618
619 out:
620 if (client)
621 med_clnt_destroy(&client);
622 return (status);
623 }
624
625 /*
626 * Try to get the address for the desired service by using the rpcbind
627 * protocol. Ignores signals.
628 */
629 static enum clnt_stat
med_get_rpcb_addr(struct knetconfig * kncfp,rpcprog_t prog,rpcvers_t vers,struct netbuf * addr)630 med_get_rpcb_addr(
631 struct knetconfig *kncfp,
632 rpcprog_t prog,
633 rpcvers_t vers,
634 struct netbuf *addr
635 )
636 {
637 int error;
638 char *ua = NULL;
639 enum clnt_stat status;
640 RPCB parms;
641 struct timeval tmo;
642 CLIENT *client = NULL;
643 k_sigset_t oldmask;
644 k_sigset_t newmask;
645 ushort_t port;
646
647 /*
648 * Call rpcbind (local or remote) to get an address we can use
649 * in an RPC client handle.
650 */
651 tmo = md_med_pmap_timeout;
652 parms.r_prog = prog;
653 parms.r_vers = vers;
654 parms.r_addr = parms.r_owner = "";
655
656 if (strcmp(kncfp->knc_protofmly, NC_INET) == 0) {
657 if (strcmp(kncfp->knc_proto, NC_TCP) == 0) {
658 parms.r_netid = "tcp";
659 } else {
660 parms.r_netid = "udp";
661 }
662 med_put_inet_port(addr, htons(PMAPPORT));
663 } else if (strcmp(kncfp->knc_protofmly, NC_LOOPBACK) == 0) {
664 parms.r_netid = "ticlts";
665 med_put_loopback_port(addr, "rpc");
666 TRIVIA((
667 "get_rpcb_addr - semantics=%s, protofmly=%s, proto=%s\n",
668 (kncfp->knc_semantics == NC_TPI_CLTS ?
669 "NC_TPI_CLTS" : "?"),
670 kncfp->knc_protofmly, kncfp->knc_proto));
671 } else {
672 TRIVIA(("get_rpcb_addr - unsupported protofmly %s\n",
673 kncfp->knc_protofmly));
674 status = RPC_UNKNOWNPROTO;
675 goto out;
676 }
677
678 /*
679 * Mask signals for the duration of the handle creation and
680 * RPC calls. This allows relatively normal operation with a
681 * signal already posted to our thread.
682 *
683 * Any further exit paths from this routine must restore
684 * the original signal mask.
685 */
686 sigfillset(&newmask);
687 sigreplace(&newmask, &oldmask);
688
689 if ((error = clnt_tli_kcreate(kncfp, addr, RPCBPROG, RPCBVERS,
690 0, 0, kcred, &client)) != 0) {
691 status = RPC_TLIERROR;
692 sigreplace(&oldmask, (k_sigset_t *)NULL);
693 MINUTE(("get_rpcb_addr - kcreate() returned %d\n", error));
694 goto out;
695 }
696
697 if (!CLNT_CONTROL(client, CLSET_NODELAYONERR, (char *)&clset)) {
698 MINUTE(("get_rpcb_addr - unable to set CLSET_NODELAYONERR\n"));
699 }
700
701 client->cl_auth = authkern_create();
702
703 if ((status = CLNT_CALL(client, RPCBPROC_GETADDR,
704 xdr_rpcb, (char *)&parms, xdr_wrapstring, (char *)&ua,
705 tmo)) != RPC_SUCCESS) {
706 sigreplace(&oldmask, (k_sigset_t *)NULL);
707 MINUTE(("get_rpcb_addr - CLNT_CALL(GETADDR) returned %d\n",
708 status));
709 goto out;
710 }
711
712 sigreplace(&oldmask, (k_sigset_t *)NULL);
713
714 if (ua == NULL || *ua == NULL) {
715 status = RPC_PROGNOTREGISTERED;
716 MINUTE(("get_rpcb_addr - program not registered\n"));
717 goto out;
718 }
719
720 /*
721 * Convert the universal address to the transport address.
722 * Theoretically, we should call the local rpcbind to translate
723 * from the universal address to the transport address, but it gets
724 * complicated (e.g., there's no direct way to tell rpcbind that we
725 * want an IP address instead of a loopback address). Note that
726 * the transport address is potentially host-specific, so we can't
727 * just ask the remote rpcbind, because it might give us the wrong
728 * answer.
729 */
730 if (strcmp(kncfp->knc_protofmly, NC_INET) == 0) {
731 port = rpc_uaddr2port(AF_INET, ua);
732 med_put_inet_port(addr, ntohs(port));
733 } else if (strcmp(kncfp->knc_protofmly, NC_LOOPBACK) == 0) {
734 loopb_u2t(ua, addr);
735 } else {
736 /* "can't happen" - should have been checked for above */
737 cmn_err(CE_PANIC, "med_get_rpcb_addr: bad protocol family");
738 }
739
740 out:
741 if (client != NULL)
742 med_clnt_destroy(&client);
743 if (ua != NULL)
744 xdr_free(xdr_wrapstring, (char *)&ua);
745 return (status);
746 }
747
748 /*
749 * Get the RPC client handle to talk to the service at addrp.
750 * Returns:
751 * RPC_SUCCESS Success.
752 * RPC_RPCBFAILURE Couldn't talk to the remote portmapper (e.g.,
753 * timeouts).
754 * RPC_INTR Caught a signal before we could successfully return.
755 * RPC_TLIERROR Couldn't initialize the handle after talking to the
756 * remote portmapper (shouldn't happen).
757 */
758 static enum clnt_stat
med_get_rpc_handle(struct knetconfig * kncfp,struct netbuf * addrp,rpcprog_t prog,rpcvers_t vers,CLIENT ** clientp)759 med_get_rpc_handle(
760 struct knetconfig *kncfp,
761 struct netbuf *addrp,
762 rpcprog_t prog,
763 rpcvers_t vers,
764 CLIENT **clientp
765 )
766 {
767 enum clnt_stat status;
768 k_sigset_t oldmask;
769 k_sigset_t newmask;
770 int error;
771
772 /*
773 * Try to get the address from either portmapper or rpcbind.
774 * We check for posted signals after trying and failing to
775 * contact the portmapper since it can take uncomfortably
776 * long for this entire procedure to time out.
777 */
778 BSTAMP
779 status = med_get_pmap_addr(kncfp, prog, vers, addrp);
780 if (MED_IS_UNRECOVERABLE_RPC(status) && status != RPC_UNKNOWNPROTO &&
781 ! PMAP_WRONG_VERSION(status)) {
782 status = RPC_RPCBFAILURE;
783 goto bailout;
784 }
785
786 if (status == RPC_SUCCESS)
787 ESTAMP("done OK med_get_pmap_addr")
788 else
789 ESTAMP("done Not OK med_get_pmap_addr")
790
791 if (status != RPC_SUCCESS) {
792 BSTAMP
793 status = med_get_rpcb_addr(kncfp, prog, vers, addrp);
794 if (status != RPC_SUCCESS) {
795 ESTAMP("done Not OK med_get_rpcb_addr")
796 MINOR((
797 "get_rpc_handle - can't contact portmapper or rpcbind\n"));
798 status = RPC_RPCBFAILURE;
799 goto bailout;
800 }
801 }
802 ESTAMP("done OK med_get_rpcb_addr")
803
804 med_clnt_destroy(clientp);
805
806 /*
807 * Mask signals for the duration of the handle creation,
808 * allowing relatively normal operation with a signal
809 * already posted to our thread.
810 *
811 * Any further exit paths from this routine must restore
812 * the original signal mask.
813 */
814 sigfillset(&newmask);
815 sigreplace(&newmask, &oldmask);
816
817 if ((error = clnt_tli_kcreate(kncfp, addrp, prog, vers,
818 0, 0, kcred, clientp)) != 0) {
819 status = RPC_TLIERROR;
820 sigreplace(&oldmask, (k_sigset_t *)NULL);
821 MINUTE(("get_rpc_handle - kcreate(prog) returned %d\n", error));
822 goto bailout;
823 }
824
825 if (!CLNT_CONTROL(*clientp, CLSET_NODELAYONERR, (char *)&clset)) {
826 MINUTE(("get_rpc_handle - unable to set CLSET_NODELAYONERR\n"));
827 }
828
829 (*clientp)->cl_auth = authkern_create();
830
831 sigreplace(&oldmask, (k_sigset_t *)NULL);
832
833 bailout:
834 return (status);
835 }
836
837 /*
838 * Return a med_client to the <prog,vers>.
839 * The med_client found is marked as in_use.
840 * It is the responsibility of the caller to release the med_client by
841 * calling med_rel_client().
842 *
843 * Returns:
844 * RPC_SUCCESS Success.
845 * RPC_CANTSEND Temporarily cannot send.
846 * RPC_TLIERROR Unspecified TLI error.
847 * RPC_UNKNOWNPROTO kncfp is from an unrecognised protocol family.
848 * RPC_PROGNOTREGISTERED The prog `prog' isn't registered on the server.
849 * RPC_RPCBFAILURE Couldn't contact portmapper on remote host.
850 * Any unsuccessful return codes from CLNT_CALL().
851 */
852 static enum clnt_stat
med_get_client(struct knetconfig * kncfp,struct netbuf * addrp,rpcprog_t prog,rpcvers_t vers,struct med_client ** mcp)853 med_get_client(
854 struct knetconfig *kncfp,
855 struct netbuf *addrp,
856 rpcprog_t prog,
857 rpcvers_t vers,
858 struct med_client **mcp
859 )
860 {
861 struct med_client *med_clnt = NULL;
862 enum clnt_stat status = RPC_SUCCESS;
863
864 mutex_enter(&med_lck);
865
866 /*
867 * Create an med_client
868 */
869 med_clnt = kmem_zalloc(sizeof (*med_clnt), KM_SLEEP);
870 med_clnt->client = NULL;
871 med_clnt->prog = prog;
872 med_clnt->vers = vers;
873 med_clnt->addr.buf = med_dup(addrp->buf, addrp->maxlen);
874 med_clnt->addr.len = addrp->len;
875 med_clnt->addr.maxlen = addrp->maxlen;
876
877 mutex_exit(&med_lck);
878
879 status = med_get_rpc_handle(kncfp, &med_clnt->addr, prog, vers,
880 &med_clnt->client);
881
882 out:
883 TRIVIA(("get_client - End: med_clnt=%p status=%d, client=%p\n",
884 (void *)med_clnt, status,
885 (med_clnt ? med_clnt->client : (void *) -1L)));
886
887 if (status == RPC_SUCCESS) {
888 *mcp = med_clnt;
889 } else {
890 /* Cleanup */
891 if (med_clnt) {
892 mutex_enter(&med_lck);
893 med_rel_client(med_clnt, EINVAL);
894 kmem_free(med_clnt, sizeof (*med_clnt));
895 mutex_exit(&med_lck);
896 }
897 *mcp = NULL;
898 }
899
900 return (status);
901 }
902
903 /*
904 * Make an RPC call to addr via config.
905 *
906 * Returns:
907 * 0 Success.
908 * EIO Couldn't get client handle, timed out, or got unexpected
909 * RPC status within md_med_protocol_retry attempts.
910 * EINVAL Unrecoverable error in RPC call. Causes client handle
911 * to be destroyed.
912 * EINTR RPC call was interrupted within md_med_protocol_retry attempts.
913 */
914 static int
med_callrpc(struct knetconfig * kncfp,struct netbuf * addrp,rpcprog_t prog,rpcvers_t vers,rpcproc_t proc,xdrproc_t inproc,caddr_t in,xdrproc_t outproc,caddr_t out,struct timeval * timout)915 med_callrpc(
916 struct knetconfig *kncfp,
917 struct netbuf *addrp,
918 rpcprog_t prog,
919 rpcvers_t vers,
920 rpcproc_t proc,
921 xdrproc_t inproc,
922 caddr_t in,
923 xdrproc_t outproc,
924 caddr_t out,
925 struct timeval *timout
926 )
927 {
928 struct med_client *med_clnt = NULL;
929 enum clnt_stat cl_stat;
930 int tries = md_med_protocol_retry;
931 int error;
932 k_sigset_t oldmask;
933 k_sigset_t newmask;
934
935 MINUTE(("med_callrpc - Calling [%u, %u, %u]\n", prog, vers, proc));
936
937 sigfillset(&newmask);
938
939 while (tries--) {
940 error = 0;
941 cl_stat = med_get_client(kncfp, addrp, prog, vers, &med_clnt);
942 if (MED_IS_UNRECOVERABLE_RPC(cl_stat)) {
943 error = EINVAL;
944 goto rel_client;
945 } else if (cl_stat != RPC_SUCCESS) {
946 error = EIO;
947 continue;
948 }
949
950 ASSERT(med_clnt != NULL);
951 ASSERT(med_clnt->client != NULL);
952
953 sigreplace(&newmask, &oldmask);
954 cl_stat = CLNT_CALL(med_clnt->client, proc, inproc, in,
955 outproc, out, *timout);
956 sigreplace(&oldmask, (k_sigset_t *)NULL);
957
958 switch (cl_stat) {
959 case RPC_SUCCESS:
960 /*
961 * Update the timestamp on the client cache entry.
962 */
963 error = 0;
964 break;
965
966 case RPC_TIMEDOUT:
967 MINOR(("med_callrpc - RPC_TIMEDOUT\n"));
968 if (timout == 0) {
969 /*
970 * We will always time out when timout == 0.
971 */
972 error = 0;
973 break;
974 }
975 /* FALLTHROUGH */
976 case RPC_CANTSEND:
977 case RPC_XPRTFAILED:
978 default:
979 if (MED_IS_UNRECOVERABLE_RPC(cl_stat)) {
980 error = EINVAL;
981 } else {
982 error = EIO;
983 }
984 }
985
986 rel_client:
987 MINOR(("med_callrpc - RPC cl_stat=%d error=%d\n",
988 cl_stat, error));
989 if (med_clnt != NULL) {
990 med_rel_client(med_clnt, error);
991 kmem_free(med_clnt, sizeof (*med_clnt));
992 }
993
994 /*
995 * If EIO, loop else we're done.
996 */
997 if (error != EIO) {
998 break;
999 }
1000 }
1001
1002 MINUTE(("med_callrpc - End: error=%d, tries=%d\n", error, tries));
1003
1004 return (error);
1005 }
1006
1007 /*
1008 * Try various transports to get the rpc call through.
1009 */
1010 static int
med_net_callrpc(char * h_nm,in_addr_t h_ip,uint_t h_flags,rpcprog_t prog,rpcvers_t vers,rpcproc_t proc,xdrproc_t inproc,caddr_t in,xdrproc_t outproc,caddr_t out,struct timeval * timout)1011 med_net_callrpc(
1012 char *h_nm,
1013 in_addr_t h_ip,
1014 uint_t h_flags,
1015 rpcprog_t prog,
1016 rpcvers_t vers,
1017 rpcproc_t proc,
1018 xdrproc_t inproc,
1019 caddr_t in,
1020 xdrproc_t outproc,
1021 caddr_t out,
1022 struct timeval *timout
1023 )
1024 {
1025 int err;
1026 struct med_addr *uap;
1027 int uapi;
1028 struct netbuf dst;
1029 int done = 0;
1030
1031 ASSERT(h_nm != NULL);
1032 ASSERT(h_ip != 0);
1033
1034 /*
1035 * Loop through our table of transports and try to get the data out.
1036 */
1037 for (uapi = 0; uapi < med_addr_tab_nents && ! done; uapi++) {
1038
1039 /* Shorthand */
1040 uap = &med_addr_tab[uapi];
1041
1042 /*
1043 * UAFLG_SKIP is used for debugging and by the protocol
1044 * selection code.
1045 */
1046 if (uap->ua_flags & UAFLG_SKIP) {
1047 MINUTE(("med_net_callrpc - %s - marked \"skip\"\n",
1048 uap->ua_netid));
1049 continue;
1050 }
1051
1052 /*
1053 * If we are not talking to this host, we can skip all LOOPBACK
1054 * transport options.
1055 */
1056 if (! (h_flags & NMIP_F_LOCAL) &&
1057 (uap->ua_flags & UAFLG_LOOPBACK))
1058 continue;
1059
1060 if (uap->ua_flags & UAFLG_ERROR)
1061 continue;
1062
1063 if (uap->ua_flags & UAFLG_RPCERROR)
1064 continue;
1065
1066 /* Unknown protocol, skip it */
1067 if (! uap->ua_kn.knc_protofmly) {
1068 MINUTE(("med_net_callrpc - bad protofmly\n"));
1069 continue;
1070 }
1071
1072 if (strcmp(uap->ua_kn.knc_protofmly, NC_LOOPBACK) == 0) {
1073 size_t alen = strlen(utsname.nodename) + 1 + 1;
1074
1075 dst.buf = kmem_zalloc(alen, KM_SLEEP);
1076 dst.maxlen = (uint_t)alen;
1077
1078 (void) strcpy(dst.buf, utsname.nodename);
1079 (void) strcat(dst.buf, ".");
1080
1081 } else if (strcmp(uap->ua_kn.knc_protofmly, NC_INET) == 0) {
1082 struct sockaddr_in *s;
1083
1084 /*
1085 * If we have not allocated a buffer for an INET addrs
1086 * or the buffer allocated will not contain an INET
1087 * addr, allocate or re-allocate.
1088 */
1089 dst.buf = kmem_zalloc(sizeof (struct sockaddr_in),
1090 KM_SLEEP);
1091 dst.maxlen = sizeof (struct sockaddr_in);
1092
1093 /* Short hand */
1094 /*LINTED*/
1095 s = (struct sockaddr_in *)dst.buf;
1096
1097 /* Initialize the socket */
1098 if (uap->ua_flags & UAFLG_LOOPBACK)
1099 s->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
1100 else
1101 s->sin_addr.s_addr = h_ip;
1102 s->sin_port = 0;
1103 s->sin_family = AF_INET;
1104 }
1105
1106 dst.len = dst.maxlen;
1107
1108 MINOR(("med_net_callrpc - Trying %s\n", uap->ua_netid));
1109
1110 err = med_callrpc(&uap->ua_kn, &dst, prog, vers, proc, inproc,
1111 in, outproc, out, timout);
1112
1113 if (dst.buf) {
1114 kmem_free(dst.buf, dst.maxlen);
1115 dst.buf = NULL;
1116 dst.len = 0;
1117 dst.maxlen = 0;
1118 }
1119
1120 if (err) {
1121 MINUTE(("med_net_callrpc - %s failed\n\n",
1122 uap->ua_netid));
1123 continue;
1124 }
1125
1126 MINUTE(("med_net_callrpc - %s OK\n\n", uap->ua_netid));
1127 done = 1;
1128 }
1129
1130 /*
1131 * Print a message if we could not reach a host.
1132 */
1133 if (! done) {
1134 cmn_err(CE_WARN, "%s on host %s not responding", MED_SERVNAME,
1135 h_nm);
1136 return (1);
1137 }
1138
1139 return (0);
1140 }
1141
1142 /*
1143 * Validate the mediator data
1144 */
1145 static int
med_ok(set_t setno,med_data_t * meddp)1146 med_ok(set_t setno, med_data_t *meddp)
1147 {
1148 /* Not initialized, or not a mediator data record */
1149 if (meddp->med_dat_mag != MED_DATA_MAGIC)
1150 goto fail;
1151
1152 MINUTE(("Magic OK\n"));
1153
1154 /* Mismatch in revisions */
1155 if (meddp->med_dat_rev != MED_DATA_REV)
1156 goto fail;
1157
1158 MINUTE(("Revision OK\n"));
1159
1160 /* Not for the right set, this is paranoid */
1161 if (setno != meddp->med_dat_sn)
1162 goto fail;
1163
1164 MINUTE(("Setno OK\n"));
1165
1166 /* The record checksum is not correct */
1167 if (crcchk(meddp, &meddp->med_dat_cks, sizeof (med_data_t), NULL))
1168 goto fail;
1169
1170 MINUTE(("Mediator validated\n"));
1171
1172 return (1);
1173
1174 fail:
1175 return (0);
1176 }
1177
1178 static void
med_adl(med_data_lst_t ** meddlpp,med_data_t * meddp)1179 med_adl(med_data_lst_t **meddlpp, med_data_t *meddp)
1180 {
1181 /*
1182 * Run to the end of the list
1183 */
1184 for (/* void */; (*meddlpp != NULL); meddlpp = &(*meddlpp)->mdl_nx)
1185 /* void */;
1186
1187 *meddlpp = (med_data_lst_t *)kmem_zalloc(sizeof (med_data_lst_t),
1188 KM_SLEEP);
1189
1190 (*meddlpp)->mdl_med = (med_data_t *)med_dup(meddp, sizeof (med_data_t));
1191 }
1192
1193 static void
mtaa_upd_init(med_thr_a_args_t * mtaap,med_thr_h_args_t * mthap)1194 mtaa_upd_init(med_thr_a_args_t *mtaap, med_thr_h_args_t *mthap)
1195 {
1196 med_upd_data_args_t *argsp;
1197 med_err_t *resp;
1198
1199 argsp = kmem_zalloc(sizeof (med_upd_data_args_t), KM_SLEEP);
1200 argsp->med.med_setno = mthap->mtha_setno;
1201 if (MD_MNSET_SETNO(argsp->med.med_setno)) {
1202 /*
1203 * In MN diskset, use a generic nodename, multiowner, in the
1204 * mediator record which allows any node to access mediator
1205 * information. MN diskset reconfig cycle forces consistent
1206 * view of set/node/drive/mediator information across all nodes
1207 * in the MN diskset. This allows the relaxation of
1208 * node name checking in rpc.metamedd for MN disksets.
1209 */
1210 argsp->med.med_caller = md_strdup(MED_MN_CALLER);
1211 } else {
1212 argsp->med.med_caller = md_strdup(utsname.nodename);
1213 }
1214 argsp->med.med_setname = md_strdup(mthap->mtha_setname);
1215 argsp->med_data = *mthap->mtha_meddp;
1216
1217 resp = kmem_zalloc(sizeof (med_err_t), KM_SLEEP);
1218
1219 mtaap->mtaa_mag = MTAA_MAGIC;
1220 mtaap->mtaa_mthap = mthap;
1221 mtaap->mtaa_prog = MED_PROG;
1222 mtaap->mtaa_vers = MED_VERS;
1223 mtaap->mtaa_proc = MED_UPD_DATA;
1224 mtaap->mtaa_inproc = xdr_med_upd_data_args_t;
1225 mtaap->mtaa_in = (caddr_t)argsp;
1226 mtaap->mtaa_outproc = xdr_med_err_t;
1227 mtaap->mtaa_out = (caddr_t)resp;
1228 mtaap->mtaa_timout = (struct timeval *)&md_med_def_timeout;
1229 }
1230
1231 static void
mtaa_upd_free(med_thr_a_args_t * mtaap)1232 mtaa_upd_free(med_thr_a_args_t *mtaap)
1233 {
1234 med_upd_data_args_t *argsp = (med_upd_data_args_t *)mtaap->mtaa_in;
1235 med_err_t *resp = (med_err_t *)mtaap->mtaa_out;
1236
1237 freestr(argsp->med.med_caller);
1238 freestr(argsp->med.med_setname);
1239 kmem_free(argsp, sizeof (med_upd_data_args_t));
1240
1241 if (mtaap->mtaa_flags & MDT_A_OK)
1242 xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
1243
1244 kmem_free(resp, sizeof (med_err_t));
1245 }
1246
1247 static int
mtaa_upd_err(med_thr_a_args_t * mtaap)1248 mtaa_upd_err(med_thr_a_args_t *mtaap)
1249 {
1250 /*LINTED*/
1251 med_err_t *resp = (med_err_t *)mtaap->mtaa_out;
1252
1253 if (resp->med_errno == MDE_MED_NOERROR) {
1254 MAJOR(("upd_med_hosts - %s - OK\n\n", mtaap->mtaa_h_nm));
1255 return (0);
1256 } else {
1257 MAJOR(("upd_med_hosts - %s - errno=%d\n\n", mtaap->mtaa_h_nm,
1258 resp->med_errno));
1259 return (1);
1260 }
1261 }
1262
1263 static void
mtaa_get_init(med_thr_a_args_t * mtaap,med_thr_h_args_t * mthap)1264 mtaa_get_init(med_thr_a_args_t *mtaap, med_thr_h_args_t *mthap)
1265 {
1266 med_args_t *argsp;
1267 med_get_data_res_t *resp;
1268
1269 argsp = kmem_zalloc(sizeof (med_args_t), KM_SLEEP);
1270 argsp->med.med_setno = mthap->mtha_setno;
1271 if (MD_MNSET_SETNO(argsp->med.med_setno)) {
1272 /*
1273 * In MN diskset, use a generic nodename, multiowner, in the
1274 * mediator record which allows any node to access mediator
1275 * information. MN diskset reconfig cycle forces consistent
1276 * view of set/node/drive/mediator information across all nodes
1277 * in the MN diskset. This allows the relaxation of
1278 * node name checking in rpc.metamedd for MN disksets.
1279 */
1280 argsp->med.med_caller = md_strdup(MED_MN_CALLER);
1281 } else {
1282 argsp->med.med_caller = md_strdup(utsname.nodename);
1283 }
1284
1285 argsp->med.med_setname = md_strdup(mthap->mtha_setname);
1286
1287 resp = kmem_zalloc(sizeof (med_get_data_res_t), KM_SLEEP);
1288
1289 mtaap->mtaa_mag = MTAA_MAGIC;
1290 mtaap->mtaa_mthap = mthap;
1291 mtaap->mtaa_prog = MED_PROG;
1292 mtaap->mtaa_vers = MED_VERS;
1293 mtaap->mtaa_proc = MED_GET_DATA;
1294 mtaap->mtaa_inproc = xdr_med_args_t;
1295 mtaap->mtaa_in = (caddr_t)argsp;
1296 mtaap->mtaa_outproc = xdr_med_get_data_res_t;
1297 mtaap->mtaa_out = (caddr_t)resp;
1298 mtaap->mtaa_timout = (struct timeval *)&md_med_def_timeout;
1299 }
1300
1301 static void
mtaa_get_free(med_thr_a_args_t * mtaap)1302 mtaa_get_free(med_thr_a_args_t *mtaap)
1303 {
1304 /*LINTED*/
1305 med_args_t *argsp = (med_args_t *)mtaap->mtaa_in;
1306 /*LINTED*/
1307 med_get_data_res_t *resp = (med_get_data_res_t *)mtaap->mtaa_out;
1308
1309 freestr(argsp->med.med_caller);
1310 freestr(argsp->med.med_setname);
1311 kmem_free(argsp, sizeof (med_args_t));
1312
1313 if (mtaap->mtaa_flags & MDT_A_OK)
1314 xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
1315
1316 kmem_free(resp, sizeof (med_get_data_res_t));
1317 }
1318
1319 static int
mtaa_get_err(med_thr_a_args_t * mtaap)1320 mtaa_get_err(med_thr_a_args_t *mtaap)
1321 {
1322 /*LINTED*/
1323 med_get_data_res_t *resp = (med_get_data_res_t *)mtaap->mtaa_out;
1324
1325 if (resp->med_status.med_errno == MDE_MED_NOERROR) {
1326 MAJOR(("get_med_host_data - %s - OK\n\n", mtaap->mtaa_h_nm));
1327 return (0);
1328 } else {
1329 MAJOR(("get_med_host_data - %s - errno=%d\n\n",
1330 mtaap->mtaa_h_nm, resp->med_status.med_errno));
1331 return (1);
1332 }
1333 }
1334
1335 static void
mtha_init(med_thr_t * mtp,med_thr_h_args_t * mthap,md_hi_t * mhp,char * setname,med_data_t * meddp,set_t setno,void (* mtaa_init_func)(med_thr_a_args_t *,med_thr_h_args_t *),int (* mtaa_err_func)(med_thr_a_args_t *))1336 mtha_init(
1337 med_thr_t *mtp,
1338 med_thr_h_args_t *mthap,
1339 md_hi_t *mhp,
1340 char *setname,
1341 med_data_t *meddp,
1342 set_t setno,
1343 void (*mtaa_init_func)(med_thr_a_args_t *,
1344 med_thr_h_args_t *),
1345 int (*mtaa_err_func)(med_thr_a_args_t *)
1346 )
1347 {
1348 int j;
1349
1350 mthap->mtha_mag = MTHA_MAGIC;
1351 mthap->mtha_mtp = mtp;
1352 mthap->mtha_mhp = mhp;
1353 mthap->mtha_setname = md_strdup(setname);
1354 if (meddp)
1355 mthap->mtha_meddp = meddp;
1356 else
1357 mthap->mtha_meddp = NULL;
1358 mthap->mtha_setno = setno;
1359 mthap->mtha_a_cnt = mhp->a_cnt;
1360 mthap->mtha_a_nthr = 0;
1361
1362 mutex_init(&mthap->mtha_a_mx, NULL, MUTEX_DEFAULT,
1363 NULL);
1364 cv_init(&mthap->mtha_a_cv, NULL, CV_DEFAULT, NULL);
1365
1366 j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
1367 for (; j >= 0; j--) {
1368 (*mtaa_init_func)(&mthap->mtha_a_args[j], mthap);
1369 mthap->mtha_a_args[j].mtaa_h_nm = mhp->a_nm[j];
1370 mthap->mtha_a_args[j].mtaa_h_ip = mhp->a_ip[j];
1371 mthap->mtha_a_args[j].mtaa_h_flags = mhp->a_flg;
1372 mthap->mtha_a_args[j].mtaa_err_func = mtaa_err_func;
1373 }
1374 }
1375
1376 static void
mtha_free(med_thr_h_args_t * mthap,void (* mtaa_free_func)(med_thr_a_args_t *))1377 mtha_free(
1378 med_thr_h_args_t *mthap,
1379 void (*mtaa_free_func)(med_thr_a_args_t *)
1380 )
1381 {
1382 int j;
1383
1384 freestr(mthap->mtha_setname);
1385
1386 j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
1387 for (; j >= 0; j--)
1388 (*mtaa_free_func)(&mthap->mtha_a_args[j]);
1389
1390 mutex_destroy(&mthap->mtha_a_mx);
1391 cv_destroy(&mthap->mtha_a_cv);
1392 }
1393
1394 static void
med_a_thr(med_thr_a_args_t * mtaap)1395 med_a_thr(med_thr_a_args_t *mtaap)
1396 {
1397 callb_cpr_t cprinfo;
1398
1399 /*
1400 * Register cpr callback
1401 */
1402 CALLB_CPR_INIT(&cprinfo, &mtaap->mtaa_mthap->mtha_a_mx,
1403 callb_generic_cpr, "med_a_thr");
1404
1405 mutex_enter(&mtaap->mtaa_mthap->mtha_a_mx);
1406 if (mtaap->mtaa_mthap->mtha_flags & MDT_H_OK)
1407 goto done;
1408
1409 mutex_exit(&mtaap->mtaa_mthap->mtha_a_mx);
1410
1411 mtaap->mtaa_err = med_net_callrpc(
1412 mtaap->mtaa_h_nm, mtaap->mtaa_h_ip, mtaap->mtaa_h_flags,
1413 mtaap->mtaa_prog, mtaap->mtaa_vers, mtaap->mtaa_proc,
1414 mtaap->mtaa_inproc, mtaap->mtaa_in,
1415 mtaap->mtaa_outproc, mtaap->mtaa_out,
1416 mtaap->mtaa_timout);
1417
1418 mutex_enter(&mtaap->mtaa_mthap->mtha_a_mx);
1419
1420 if (mtaap->mtaa_err) {
1421 MAJOR(("med_net_callrpc(%u, %u, %u) - %s - failed\n\n",
1422 mtaap->mtaa_prog, mtaap->mtaa_vers, mtaap->mtaa_proc,
1423 mtaap->mtaa_h_nm));
1424 xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
1425 } else {
1426 if ((*mtaap->mtaa_err_func)(mtaap) == 0) {
1427 if (! (mtaap->mtaa_mthap->mtha_flags & MDT_H_OK)) {
1428 mtaap->mtaa_mthap->mtha_flags |= MDT_H_OK;
1429 mtaap->mtaa_flags |= MDT_A_OK;
1430 } else
1431 xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
1432 } else
1433 xdr_free(mtaap->mtaa_outproc, mtaap->mtaa_out);
1434 }
1435
1436 done:
1437 mtaap->mtaa_mthap->mtha_a_nthr--;
1438 cv_signal(&mtaap->mtaa_mthap->mtha_a_cv);
1439
1440 /*
1441 * CALLB_CPR_EXIT will do mutex_exit(&mtaap->mtaa_mthap->mtha_a_mx)
1442 */
1443 CALLB_CPR_EXIT(&cprinfo);
1444 thread_exit();
1445 }
1446
1447 static void
med_h_thr(med_thr_h_args_t * mthap)1448 med_h_thr(med_thr_h_args_t *mthap)
1449 {
1450 int j;
1451 callb_cpr_t cprinfo;
1452
1453 /*
1454 * Register cpr callback
1455 */
1456 CALLB_CPR_INIT(&cprinfo, &mthap->mtha_mtp->mt_mx, callb_generic_cpr,
1457 "med_a_thr");
1458 /*
1459 * Lock mthap->mtha_mtp->mt_mx is held early to avoid releasing the
1460 * locks out of order.
1461 */
1462 mutex_enter(&mthap->mtha_mtp->mt_mx);
1463 mutex_enter(&mthap->mtha_a_mx);
1464
1465 j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
1466 for (; j >= 0; j--) {
1467 (void) thread_create(NULL, 0, med_a_thr,
1468 &mthap->mtha_a_args[j], 0, &p0, TS_RUN, minclsyspri);
1469 mthap->mtha_a_nthr++;
1470 }
1471
1472 /*
1473 * cpr safe to suspend while waiting for other threads
1474 */
1475 CALLB_CPR_SAFE_BEGIN(&cprinfo);
1476 while (mthap->mtha_a_nthr > 0)
1477 cv_wait(&mthap->mtha_a_cv, &mthap->mtha_a_mx);
1478 mutex_exit(&mthap->mtha_a_mx);
1479 CALLB_CPR_SAFE_END(&cprinfo, &mthap->mtha_mtp->mt_mx);
1480
1481
1482 mthap->mtha_mtp->mt_nthr--;
1483 cv_signal(&mthap->mtha_mtp->mt_cv);
1484
1485 /*
1486 * set up cpr exit
1487 * CALLB_CPR_EXIT will do mutex_exit(&mtaap->mta_mtp->mt_mx)
1488 */
1489 CALLB_CPR_EXIT(&cprinfo);
1490 thread_exit();
1491 }
1492
1493 static med_get_data_res_t *
mtaa_get_resp(med_thr_h_args_t * mthap)1494 mtaa_get_resp(med_thr_h_args_t *mthap)
1495 {
1496 med_thr_a_args_t *mtaap;
1497 int j;
1498
1499 j = MIN(mthap->mtha_a_cnt, MAX_HOST_ADDRS) - 1;
1500 for (; j >= 0; j--) {
1501 mtaap = &mthap->mtha_a_args[j];
1502 if (mtaap->mtaa_flags & MDT_A_OK)
1503 /*LINTED*/
1504 return ((med_get_data_res_t *)mtaap->mtaa_out);
1505 }
1506 return ((med_get_data_res_t *)NULL);
1507 }
1508
1509 /*
1510 * Public Functions
1511 */
1512
1513 /*
1514 * initializes med structs, locks, etc
1515 */
1516 void
med_init(void)1517 med_init(void)
1518 {
1519 int uapi;
1520
1521 TRIVIA(("[med_init"));
1522
1523 for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
1524 struct med_addr *uap = &med_addr_tab[uapi];
1525
1526 /* If the protocol is skipped, the mutex is not needed either */
1527 if (md_med_trans_lst != NULL &&
1528 strstr(md_med_trans_lst, uap->ua_kn.knc_proto) == NULL &&
1529 strstr(md_med_trans_lst, uap->ua_netid) == NULL) {
1530 uap->ua_flags |= UAFLG_SKIP;
1531 continue;
1532 }
1533
1534 mutex_init(&uap->ua_mutex, NULL, MUTEX_DEFAULT, NULL);
1535 uap->ua_flags |= UAFLG_LOCKINIT;
1536 bzero((caddr_t)&uap->ua_kn.knc_unused,
1537 sizeof (uap->ua_kn.knc_unused));
1538 }
1539
1540 TRIVIA(("]\n"));
1541 }
1542
1543 /*
1544 * free any med structs, locks, etc
1545 */
1546 void
med_fini(void)1547 med_fini(void)
1548 {
1549 int uapi;
1550
1551 TRIVIA(("[med_fini"));
1552
1553 for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
1554 struct med_addr *uap = &med_addr_tab[uapi];
1555
1556 if (uap->ua_flags & UAFLG_LOCKINIT) {
1557 mutex_destroy(&uap->ua_mutex);
1558 uap->ua_flags &= ~UAFLG_LOCKINIT;
1559 }
1560 }
1561
1562 TRIVIA(("]\n"));
1563 }
1564
1565 /*
1566 * Update all the mediators
1567 */
1568 int
upd_med_hosts(md_hi_arr_t * mp,char * setname,med_data_t * meddp,char * caller)1569 upd_med_hosts(
1570 md_hi_arr_t *mp,
1571 char *setname,
1572 med_data_t *meddp,
1573 char *caller
1574 )
1575 {
1576 med_thr_t *mtp;
1577 med_thr_h_args_t *mthap;
1578 int i;
1579 int medok = 0;
1580
1581 MAJOR(("upd_med_hosts - called from <%s>\n", NULLSTR(caller)));
1582
1583 /* No mediators, were done */
1584 if (mp->n_cnt == 0)
1585 return (0);
1586
1587 mtp = kmem_zalloc(sizeof (med_thr_t), KM_SLEEP);
1588 ASSERT(mtp != NULL);
1589
1590 mutex_init(&mtp->mt_mx, NULL, MUTEX_DEFAULT, NULL);
1591 cv_init(&mtp->mt_cv, NULL, CV_DEFAULT, NULL);
1592 mtp->mt_mag = MTH_MAGIC;
1593
1594 mutex_enter(&mtp->mt_mx);
1595
1596 mtp->mt_nthr = 0;
1597
1598 /* Loop through our list of mediator hosts, start a thread per host */
1599 for (i = 0; i < md_nmedh; i++) {
1600
1601 if (mp->n_lst[i].a_cnt == 0)
1602 continue;
1603
1604 mtp->mt_h_args[i] = kmem_zalloc(sizeof (med_thr_h_args_t),
1605 KM_SLEEP);
1606 mthap = mtp->mt_h_args[i];
1607 ASSERT(mthap != NULL);
1608 mtha_init(mtp, mthap, &mp->n_lst[i], setname, meddp,
1609 meddp->med_dat_sn, mtaa_upd_init, mtaa_upd_err);
1610
1611 MAJOR(("upd_med_hosts - updating %s\n",
1612 NULLSTR(mp->n_lst[i].a_nm[0])));
1613
1614 (void) thread_create(NULL, 0, med_h_thr, mthap, 0, &p0,
1615 TS_RUN, minclsyspri);
1616
1617 mtp->mt_nthr++;
1618 }
1619
1620 while (mtp->mt_nthr > 0)
1621 cv_wait(&mtp->mt_cv, &mtp->mt_mx);
1622
1623 mutex_exit(&mtp->mt_mx);
1624
1625 for (i = 0; i < md_nmedh; i++) {
1626 mthap = mtp->mt_h_args[i];
1627 if (mthap != NULL) {
1628 if (mthap->mtha_flags & MDT_H_OK)
1629 medok++;
1630 mtha_free(mthap, mtaa_upd_free);
1631 kmem_free(mthap, sizeof (med_thr_h_args_t));
1632 }
1633 }
1634
1635 mutex_destroy(&mtp->mt_mx);
1636 cv_destroy(&mtp->mt_cv);
1637
1638 kmem_free(mtp, sizeof (med_thr_t));
1639
1640 return (medok);
1641 }
1642
1643 /*
1644 * Get the mediator data.
1645 */
1646 med_data_lst_t *
get_med_host_data(md_hi_arr_t * mp,char * setname,set_t setno)1647 get_med_host_data(
1648 md_hi_arr_t *mp,
1649 char *setname,
1650 set_t setno
1651 )
1652 {
1653 med_thr_t *mtp;
1654 med_thr_h_args_t *mthap;
1655 med_get_data_res_t *resp;
1656 med_data_lst_t *retval = NULL;
1657 int i;
1658
1659 /* No mediators, were done */
1660 if (mp->n_cnt == 0)
1661 return (NULL);
1662
1663 mtp = kmem_zalloc(sizeof (med_thr_t), KM_SLEEP);
1664 ASSERT(mtp != NULL);
1665
1666 mutex_init(&mtp->mt_mx, NULL, MUTEX_DEFAULT, NULL);
1667 cv_init(&mtp->mt_cv, NULL, CV_DEFAULT, NULL);
1668
1669 mutex_enter(&mtp->mt_mx);
1670
1671 mtp->mt_nthr = 0;
1672
1673 /* Loop through our list of mediator hosts, start a thread per host */
1674 for (i = 0; i < md_nmedh; i++) {
1675
1676 if (mp->n_lst[i].a_cnt == 0)
1677 continue;
1678
1679 mtp->mt_h_args[i] = kmem_zalloc(sizeof (med_thr_h_args_t),
1680 KM_SLEEP);
1681 mthap = mtp->mt_h_args[i];
1682 ASSERT(mthap != NULL);
1683 mtha_init(mtp, mthap, &mp->n_lst[i], setname, NULL, setno,
1684 mtaa_get_init, mtaa_get_err);
1685
1686 MAJOR(("get_med_host_data from %s\n",
1687 NULLSTR(mp->n_lst[i].a_nm[0])));
1688
1689 (void) thread_create(NULL, 0, med_h_thr, mthap, 0, &p0,
1690 TS_RUN, minclsyspri);
1691
1692 mtp->mt_nthr++;
1693 }
1694
1695 while (mtp->mt_nthr > 0)
1696 cv_wait(&mtp->mt_cv, &mtp->mt_mx);
1697
1698 mutex_exit(&mtp->mt_mx);
1699
1700 for (i = 0; i < md_nmedh; i++) {
1701 mthap = mtp->mt_h_args[i];
1702 if (mthap != NULL) {
1703 if (mthap->mtha_flags & MDT_H_OK) {
1704 resp = mtaa_get_resp(mthap);
1705 ASSERT(resp != NULL);
1706
1707 if (med_ok(setno, &resp->med_data))
1708 med_adl(&retval, &resp->med_data);
1709 }
1710 mtha_free(mthap, mtaa_get_free);
1711 kmem_free(mthap, sizeof (med_thr_h_args_t));
1712 }
1713 }
1714
1715 mutex_destroy(&mtp->mt_mx);
1716 cv_destroy(&mtp->mt_cv);
1717
1718 kmem_free(mtp, sizeof (med_thr_t));
1719
1720 return (retval);
1721 }
1722
1723 int
med_get_t_size_ioctl(mddb_med_t_parm_t * tpp,int mode)1724 med_get_t_size_ioctl(mddb_med_t_parm_t *tpp, int mode)
1725 {
1726 md_error_t *ep = &tpp->med_tp_mde;
1727
1728 mdclrerror(ep);
1729
1730 if ((mode & FREAD) == 0)
1731 return (mdsyserror(ep, EACCES));
1732
1733 tpp->med_tp_nents = med_addr_tab_nents;
1734 tpp->med_tp_setup = md_med_transdevs_set;
1735
1736 return (0);
1737 }
1738
1739 int
med_get_t_ioctl(mddb_med_t_parm_t * tpp,int mode)1740 med_get_t_ioctl(mddb_med_t_parm_t *tpp, int mode)
1741 {
1742 md_error_t *ep = &tpp->med_tp_mde;
1743 int uapi = 0;
1744
1745 mdclrerror(ep);
1746
1747 if ((mode & FREAD) == 0)
1748 return (mdsyserror(ep, EACCES));
1749
1750 for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
1751 struct med_addr *uap = &med_addr_tab[uapi];
1752
1753 (void) strncpy(tpp->med_tp_ents[uapi].med_te_nm,
1754 uap->ua_devname, MED_TE_NM_LEN);
1755 tpp->med_tp_ents[uapi].med_te_dev =
1756 (md_dev64_t)uap->ua_kn.knc_rdev;
1757 }
1758
1759 tpp->med_tp_nents = med_addr_tab_nents;
1760
1761 return (0);
1762 }
1763
1764 int
med_set_t_ioctl(mddb_med_t_parm_t * tpp,int mode)1765 med_set_t_ioctl(mddb_med_t_parm_t *tpp, int mode)
1766 {
1767 md_error_t *ep = &tpp->med_tp_mde;
1768 int uapi = 0;
1769
1770 mdclrerror(ep);
1771
1772 if ((mode & FWRITE) == 0)
1773 return (mdsyserror(ep, EACCES));
1774
1775 for (uapi = 0; uapi < med_addr_tab_nents; uapi++) {
1776 struct med_addr *uap = &med_addr_tab[uapi];
1777
1778 mutex_enter(&uap->ua_mutex);
1779 uap->ua_kn.knc_rdev = md_dev64_to_dev(
1780 tpp->med_tp_ents[uapi].med_te_dev);
1781 mutex_exit(&uap->ua_mutex);
1782 }
1783
1784 md_med_transdevs_set = 1;
1785
1786 return (0);
1787 }
1788