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 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Just in case we're not in a build environment, make sure that
29 * TEXT_DOMAIN gets set to something.
30 */
31 #if !defined(TEXT_DOMAIN)
32 #define TEXT_DOMAIN "SYS_TEST"
33 #endif
34
35 /*
36 * Mediator functions
37 */
38
39 #include <meta.h>
40 #include <metamed.h>
41 #include <dlfcn.h>
42 #include <sdssc.h>
43
44 /*
45 * There are too many external factors that affect the timing of the
46 * operations, so we set the timeout to a very large value, in this
47 * case 1 day, which should handle HW timeouts, large configurations,
48 * and other potential delays.
49 */
50 #define CL_LONG_TMO 86400L /* 1 day */
51 #define CL_MEDIUM_TMO 3600L /* 1 hour */
52 #define CL_SHORT_TMO 600L /* 10 minutes */
53 #define CL_DEF_TMO 10L /* 10 seconds */
54
55 static md_timeval32_t def_rpcb_timeout = { MD_CLNT_CREATE_TOUT, 0 };
56
57 /*
58 * RPC handle
59 */
60 typedef struct {
61 char *hostname;
62 CLIENT *clntp;
63 } med_handle_t;
64
65 /*
66 * Data to be sent from med_clnt_create_timed to med_create_helper via
67 * meta_client_create_retry.
68 */
69 typedef struct {
70 rpcprog_t mcd_program; /* RPC program designation */
71 rpcvers_t mcd_version; /* RPC version */
72 char *mcd_nettype; /* Type of network to use for RPC */
73 } med_create_data_t;
74
75 /*
76 * Perform the work of actually doing the clnt_create for
77 * meta_client_create_retry.
78 */
79 static CLIENT *
med_create_helper(char * hostname,void * private,struct timeval * time_out)80 med_create_helper(char *hostname, void *private, struct timeval *time_out)
81 {
82 med_create_data_t *cd = (med_create_data_t *)private;
83
84 return (clnt_create_timed(hostname, cd->mcd_program, cd->mcd_version,
85 cd->mcd_nettype, time_out));
86 }
87
88 static
med_clnt_create_timed(char * hostname,const ulong_t prog,const ulong_t vers,char * nettype,const md_timeval32_t * tp)89 CLIENT *med_clnt_create_timed(
90 char *hostname,
91 const ulong_t prog,
92 const ulong_t vers,
93 char *nettype,
94 const md_timeval32_t *tp
95 )
96 {
97 med_create_data_t cd; /* Create data. */
98
99 cd.mcd_program = prog;
100 cd.mcd_version = vers;
101 cd.mcd_nettype = nettype;
102 return (meta_client_create_retry(hostname, med_create_helper,
103 (void *)&cd, (time_t)tp->tv_sec, NULL));
104 }
105
106 /*
107 * Set the timeout value for this client handle.
108 */
109 static int
cl_sto_medd(CLIENT * clntp,char * hostname,long time_out,md_error_t * ep)110 cl_sto_medd(
111 CLIENT *clntp,
112 char *hostname,
113 long time_out,
114 md_error_t *ep
115 )
116 {
117 md_timeval32_t nto;
118
119 (void) memset(&nto, '\0', sizeof (nto));
120
121 nto.tv_sec = time_out;
122
123 if (clnt_control(clntp, CLSET_TIMEOUT, (char *)&nto) != TRUE)
124 return (mdrpcerror(ep, clntp, hostname,
125 dgettext(TEXT_DOMAIN, "metad client set timeout")));
126
127 return (0);
128 }
129
130 /*
131 * close RPC connection
132 */
133 static void
close_medd(med_handle_t * hp)134 close_medd(
135 med_handle_t *hp
136 )
137 {
138 assert(hp != NULL);
139 if (hp->hostname != NULL) {
140 Free(hp->hostname);
141 }
142 if (hp->clntp != NULL) {
143 auth_destroy(hp->clntp->cl_auth);
144 clnt_destroy(hp->clntp);
145 }
146 Free(hp);
147 }
148
149 /*
150 * open RPC connection to rpc.medd
151 */
152 static med_handle_t *
open_medd(char * hostname,long time_out,md_error_t * ep)153 open_medd(
154 char *hostname,
155 long time_out,
156 md_error_t *ep
157 )
158 {
159 CLIENT *clntp;
160 med_handle_t *hp;
161
162 /* default to local host */
163 if ((hostname == NULL) || (*hostname == '\0'))
164 hostname = mynode();
165
166 /* open RPC connection */
167 assert(hostname != NULL);
168 if ((clntp = med_clnt_create_timed(hostname, MED_PROG, MED_VERS,
169 "tcp", &def_rpcb_timeout)) == NULL) {
170 if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED)
171 clnt_pcreateerror(hostname);
172 (void) mdrpccreateerror(ep, hostname,
173 "medd med_clnt_create_timed");
174 return (NULL);
175 } else {
176 auth_destroy(clntp->cl_auth);
177 clntp->cl_auth = authsys_create_default();
178 assert(clntp->cl_auth != NULL);
179 }
180
181 if (cl_sto_medd(clntp, hostname, time_out, ep) != 0)
182 return (NULL);
183
184 /* return connection */
185 hp = Zalloc(sizeof (*hp));
186 hp->hostname = Strdup(hostname);
187 hp->clntp = clntp;
188
189 return (hp);
190 }
191
192 /*
193 * steal and convert med_err_t
194 */
195 int
meddstealerror(md_error_t * ep,med_err_t * medep)196 meddstealerror(
197 md_error_t *ep,
198 med_err_t *medep
199 )
200 {
201 char buf[BUFSIZ];
202 char *p = buf;
203 size_t psize = BUFSIZ;
204 char *emsg;
205 int rval = -1;
206
207 /* no error */
208 if (medep->med_errno == 0) {
209 /* assert(medep->name == NULL); */
210 rval = 0;
211 goto out;
212 }
213
214 /* steal error */
215 if ((medep->med_node != NULL) && (medep->med_node[0] != '\0')) {
216 (void) snprintf(p, psize, "%s: ", medep->med_node);
217 p = &buf[strlen(buf)];
218 psize = buf + BUFSIZ - p;
219 }
220
221 if ((medep->med_misc != NULL) && (medep->med_misc[0] != '\0')) {
222 (void) snprintf(p, psize, "%s: ", medep->med_misc);
223 p = &buf[strlen(buf)];
224 psize = buf + BUFSIZ - p;
225 }
226
227 if (medep->med_errno < 0) {
228 if ((emsg = med_errnum_to_str(medep->med_errno)) != NULL)
229 (void) snprintf(p, psize, "%s", emsg);
230 else
231 (void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
232 "unknown mediator errno %d\n"), medep->med_errno);
233 } else {
234 if ((emsg = strerror(medep->med_errno)) != NULL)
235 (void) snprintf(p, psize, "%s", emsg);
236 else
237 (void) snprintf(p, psize, dgettext(TEXT_DOMAIN,
238 "errno %d out of range"), medep->med_errno);
239 }
240 (void) mderror(ep, MDE_MED_ERROR, buf);
241
242 /* cleanup, return success */
243 out:
244 if (medep->med_node != NULL)
245 Free(medep->med_node);
246 if (medep->med_misc != NULL)
247 Free(medep->med_misc);
248 (void) memset(medep, 0, sizeof (*medep));
249 return (rval);
250 }
251
252 static med_handle_t *
open_medd_wrap(md_h_t * mdhp,long time_out,md_error_t * ep)253 open_medd_wrap(
254 md_h_t *mdhp,
255 long time_out,
256 md_error_t *ep
257 )
258 {
259 med_handle_t *hp = NULL;
260 int i;
261 char *hnm;
262
263 assert(mdhp && mdhp->a_cnt > 0);
264
265 /* Loop through the hosts listed */
266 i = min(mdhp->a_cnt, MAX_HOST_ADDRS) - 1;
267 for (; i >= 0; i--) {
268 hnm = mdhp->a_nm[i];
269
270 if ((hp = open_medd(hnm, time_out, ep)) == NULL) {
271 if (mdanyrpcerror(ep) && i != 0) {
272 mdclrerror(ep);
273 continue;
274 }
275 }
276 return (hp);
277 }
278
279 rpc_createerr.cf_stat = RPC_CANTSEND;
280 rpc_createerr.cf_error.re_status = 0;
281 (void) mdrpccreateerror(ep, mdhp->a_nm[0],
282 dgettext(TEXT_DOMAIN, "medd open wrap"));
283
284 return (NULL);
285 }
286
287 static int
setup_med_transtab(md_error_t * ep)288 setup_med_transtab(md_error_t *ep)
289 {
290 mddb_med_t_parm_t *tp = NULL;
291 struct stat statb;
292 int i;
293 size_t alloc_size = 0;
294 int err = 0;
295
296
297 if ((tp = Zalloc(sizeof (mddb_med_t_parm_t))) == NULL)
298 return (mdsyserror(ep, ENOMEM, "setup_med_transtab"));
299
300 if (metaioctl(MD_MED_GET_TLEN, tp, &tp->med_tp_mde, NULL) != 0) {
301 err = mdstealerror(ep, &tp->med_tp_mde);
302 goto out;
303 }
304
305 if (tp->med_tp_setup == 1)
306 goto out;
307
308 alloc_size = (sizeof (mddb_med_t_parm_t) - sizeof (mddb_med_t_ent_t)) +
309 (sizeof (mddb_med_t_ent_t) * tp->med_tp_nents);
310
311 if ((tp = Realloc(tp, alloc_size)) == NULL) {
312 err = mdsyserror(ep, ENOMEM, "setup_med_transtab");
313 goto out;
314 }
315
316 if (metaioctl(MD_MED_GET_T, tp, &tp->med_tp_mde, NULL) != 0) {
317 err = mdstealerror(ep, &tp->med_tp_mde);
318 goto out;
319 }
320
321 for (i = 0; i < tp->med_tp_nents; i++) {
322 if (meta_stat(tp->med_tp_ents[i].med_te_nm, &statb) == -1) {
323 md_perror("setup_med_transtab(): stat():");
324 tp->med_tp_ents[i].med_te_dev = NODEV64;
325 } else {
326 tp->med_tp_ents[i].med_te_dev =
327 meta_expldev(statb.st_rdev);
328 }
329 }
330
331 if (metaioctl(MD_MED_SET_T, tp, &tp->med_tp_mde, NULL) != 0)
332 err = mdstealerror(ep, &tp->med_tp_mde);
333
334 out:
335 Free(tp);
336 return (err);
337 }
338
339 /*
340 * Externals
341 */
342
343 /*
344 * NULLPROC - just returns a response
345 */
346 int
clnt_med_null(char * hostname,md_error_t * ep)347 clnt_med_null(
348 char *hostname,
349 md_error_t *ep
350 )
351 {
352 med_handle_t *hp;
353 med_err_t res;
354
355 /* initialize */
356 mdclrerror(ep);
357
358 /* do it */
359 if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
360 return (-1);
361
362 if (med_null_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
363 (void) mdrpcerror(ep, hp->clntp, hostname,
364 dgettext(TEXT_DOMAIN, "medd nullproc"));
365
366 close_medd(hp);
367
368 xdr_free(xdr_med_err_t, (char *)&res);
369
370 if (! mdisok(ep))
371 return (-1);
372
373 return (0);
374 }
375
376 /*
377 * Update the mediator information on the mediator.
378 * This function does the same functionality as
379 * clnt_med_upd_data() except that it takes different
380 * argument so that host which is just a mediator, can
381 * still update its mediator record.
382 */
383 int
clnt_user_med_upd_data(md_h_t * mdhp,bool_t obandiskset,char * setname,uint_t setnum,med_data_t * meddp,md_error_t * ep)384 clnt_user_med_upd_data(
385 md_h_t *mdhp,
386 bool_t obandiskset,
387 char *setname,
388 uint_t setnum,
389 med_data_t *meddp,
390 md_error_t *ep
391 )
392 {
393 med_handle_t *hp;
394 med_upd_data_args_t args;
395 med_err_t res;
396
397 /* Initialize */
398 mdclrerror(ep);
399 (void) memset(&args, 0, sizeof (args));
400 (void) memset(&res, 0, sizeof (res));
401
402 /* Build args */
403 if (obandiskset)
404 args.med.med_caller = Strdup(MED_MN_CALLER);
405 else
406 args.med.med_caller = Strdup(mynode());
407
408 args.med.med_setname = Strdup(setname);
409 args.med.med_setno = setnum;
410 args.med_data = *meddp;
411
412 if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
413 return (-1);
414
415 if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
416 (void) mdrpcerror(ep, hp->clntp, hp->hostname,
417 dgettext(TEXT_DOMAIN, "medd get record"));
418 else
419 (void) meddstealerror(ep, &res);
420
421 close_medd(hp);
422
423 xdr_free(xdr_med_upd_data_args_t, (char *)&args);
424 xdr_free(xdr_med_err_t, (char *)&res);
425
426 if (! mdisok(ep))
427 return (-1);
428
429 return (0);
430 }
431
432 /*
433 * Get the mediator information from the client.
434 * The code does same functinality as clnt_med_get_data()
435 * except that it takes different arguments so that
436 * host which doesn't have set information, can still
437 * get access to mediator information
438 */
439 int
clnt_user_med_get_data(md_h_t * mdhp,bool_t obandiskset,char * setname,uint_t setnum,med_data_t * meddp,md_error_t * ep)440 clnt_user_med_get_data(
441 md_h_t *mdhp,
442 bool_t obandiskset,
443 char *setname,
444 uint_t setnum,
445 med_data_t *meddp,
446 md_error_t *ep
447 )
448 {
449 int rval = -1;
450 med_handle_t *hp;
451 med_args_t args;
452 med_get_data_res_t res;
453
454 /* Initialize */
455 mdclrerror(ep);
456 (void) memset(&args, 0, sizeof (args));
457 (void) memset(&res, 0, sizeof (res));
458
459 /* Build args */
460 if (obandiskset)
461 args.med.med_caller = Strdup(MED_MN_CALLER);
462 else
463 args.med.med_caller = Strdup(mynode());
464
465 args.med.med_setname = Strdup(setname);
466 args.med.med_setno = setnum;
467
468 if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
469 return (-1);
470
471 if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
472 (void) mdrpcerror(ep, hp->clntp, hp->hostname,
473 dgettext(TEXT_DOMAIN, "medd get record"));
474 else
475 (void) meddstealerror(ep, &res.med_status);
476
477 close_medd(hp);
478
479 if (mdisok(ep)) {
480 /* copy the mediator data in meddp */
481 (void) memmove(meddp, &res.med_data, sizeof (med_data_t));
482 rval = 0;
483 }
484
485 xdr_free(xdr_med_args_t, (char *)&args);
486 xdr_free(xdr_med_get_data_res_t, (char *)&res);
487
488 return (rval);
489 }
490
491
492 /*
493 * Update the mediator information on the mediator.
494 * *** This is not normally called from user code, the kernel does this! ***
495 */
496 int
clnt_med_upd_data(md_h_t * mdhp,mdsetname_t * sp,med_data_t * meddp,md_error_t * ep)497 clnt_med_upd_data(
498 md_h_t *mdhp,
499 mdsetname_t *sp,
500 med_data_t *meddp,
501 md_error_t *ep
502 )
503 {
504 med_handle_t *hp;
505 med_upd_data_args_t args;
506 med_err_t res;
507 md_set_desc *sd;
508
509 /* initialize */
510 mdclrerror(ep);
511 (void) memset(&args, 0, sizeof (args));
512 (void) memset(&res, 0, sizeof (res));
513
514 /* build args */
515 if ((sd = metaget_setdesc(sp, ep)) == NULL)
516 return (-1);
517
518 if (MD_MNSET_DESC(sd))
519 /*
520 * In the MN diskset, use a generic nodename, multiowner, as
521 * the node initiating the RPC request. This allows
522 * any node to access mediator information.
523 *
524 * MN diskset reconfig cycle forces consistent
525 * view of set/node/drive/mediator information across all nodes
526 * in the MN diskset. This allows the relaxation of
527 * node name checking in rpc.metamedd for MN disksets.
528 *
529 * In the traditional diskset, only a calling node that is
530 * in the mediator record's diskset nodelist can access
531 * mediator data.
532 */
533 args.med.med_caller = Strdup(MED_MN_CALLER);
534 else
535 args.med.med_caller = Strdup(mynode());
536 args.med.med_setname = Strdup(sp->setname);
537 args.med.med_setno = sp->setno;
538 args.med_data = *meddp;
539
540 /* do it */
541 if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
542 return (-1);
543
544 if (med_upd_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
545 (void) mdrpcerror(ep, hp->clntp, hp->hostname,
546 dgettext(TEXT_DOMAIN, "medd update data"));
547 else
548 (void) meddstealerror(ep, &res);
549
550 close_medd(hp);
551
552 xdr_free(xdr_med_upd_data_args_t, (char *)&args);
553 xdr_free(xdr_med_err_t, (char *)&res);
554
555 if (! mdisok(ep))
556 return (-1);
557
558 return (0);
559 }
560
561 /*
562 * Get the mediator data for this client from the mediator
563 */
564 int
clnt_med_get_data(md_h_t * mdhp,mdsetname_t * sp,med_data_t * meddp,md_error_t * ep)565 clnt_med_get_data(
566 md_h_t *mdhp,
567 mdsetname_t *sp,
568 med_data_t *meddp,
569 md_error_t *ep
570 )
571 {
572 med_handle_t *hp;
573 med_args_t args;
574 med_get_data_res_t res;
575 int rval = -1;
576 md_set_desc *sd;
577
578 /* initialize */
579 mdclrerror(ep);
580 (void) memset(&args, 0, sizeof (args));
581 (void) memset(&res, 0, sizeof (res));
582
583 /* build args */
584 if ((sd = metaget_setdesc(sp, ep)) == NULL)
585 return (-1);
586
587 if (MD_MNSET_DESC(sd))
588 /*
589 * In the MN diskset, use a generic nodename, multiowner, as
590 * the node initiating the RPC request. This allows
591 * any node to access mediator information.
592 *
593 * MN diskset reconfig cycle forces consistent
594 * view of set/node/drive/mediator information across all nodes
595 * in the MN diskset. This allows the relaxation of
596 * node name checking in rpc.metamedd for MN disksets.
597 *
598 * In the traditional diskset, only a calling node that is
599 * in the mediator record's diskset nodelist can access
600 * mediator data.
601 */
602 args.med.med_caller = Strdup(MED_MN_CALLER);
603 else
604 args.med.med_caller = Strdup(mynode());
605 args.med.med_setname = Strdup(sp->setname);
606 args.med.med_setno = sp->setno;
607
608 /* do it */
609 if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
610 return (-1);
611
612 if (med_get_data_1(&args, &res, hp->clntp) != RPC_SUCCESS)
613 (void) mdrpcerror(ep, hp->clntp, hp->hostname,
614 dgettext(TEXT_DOMAIN, "medd get data"));
615 else
616 (void) meddstealerror(ep, &res.med_status);
617
618 close_medd(hp);
619
620 if (mdisok(ep)) {
621 /* do something with the results */
622 (void) memmove(meddp, &res.med_data, sizeof (med_data_t));
623 rval = 0;
624 }
625
626 xdr_free(xdr_med_args_t, (char *)&args);
627 xdr_free(xdr_med_get_data_res_t, (char *)&res);
628
629 return (rval);
630 }
631
632 /*
633 * Update the mediator record on the mediator.
634 */
635 int
clnt_med_upd_rec(md_h_t * mdhp,mdsetname_t * sp,med_rec_t * medrp,md_error_t * ep)636 clnt_med_upd_rec(
637 md_h_t *mdhp,
638 mdsetname_t *sp,
639 med_rec_t *medrp,
640 md_error_t *ep
641 )
642 {
643 med_handle_t *hp;
644 med_upd_rec_args_t args;
645 med_err_t res;
646 md_set_desc *sd;
647
648 /* initialize */
649 mdclrerror(ep);
650 (void) memset(&args, 0, sizeof (args));
651 (void) memset(&res, 0, sizeof (res));
652
653 /* build args */
654 if ((sd = metaget_setdesc(sp, ep)) == NULL)
655 return (-1);
656
657 if (MD_MNSET_DESC(sd))
658 /*
659 * In the MN diskset, use a generic nodename, multiowner, as
660 * the node initiating the RPC request. This allows
661 * any node to access mediator information.
662 *
663 * MN diskset reconfig cycle forces consistent
664 * view of set/node/drive/mediator information across all nodes
665 * in the MN diskset. This allows the relaxation of
666 * node name checking in rpc.metamedd for MN disksets.
667 *
668 * In the traditional diskset, only a calling node that is
669 * in the mediator record's diskset nodelist can access
670 * mediator data.
671 */
672 args.med.med_caller = Strdup(MED_MN_CALLER);
673 else
674 args.med.med_caller = Strdup(mynode());
675 args.med.med_setname = Strdup(sp->setname);
676 args.med.med_setno = sp->setno;
677 args.med_flags = 0;
678 args.med_rec = *medrp; /* structure assignment */
679
680 /* do it */
681 if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
682 return (-1);
683
684 if (med_upd_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
685 (void) mdrpcerror(ep, hp->clntp, hp->hostname,
686 dgettext(TEXT_DOMAIN, "medd update record"));
687 else
688 (void) meddstealerror(ep, &res);
689
690 close_medd(hp);
691
692 xdr_free(xdr_med_upd_rec_args_t, (char *)&args);
693 xdr_free(xdr_med_err_t, (char *)&res);
694
695 if (! mdisok(ep))
696 return (-1);
697
698 return (0);
699 }
700
701 /*
702 * Get the mediator record for this client from the mediator
703 */
704 int
clnt_med_get_rec(md_h_t * mdhp,mdsetname_t * sp,med_rec_t * medrp,md_error_t * ep)705 clnt_med_get_rec(
706 md_h_t *mdhp,
707 mdsetname_t *sp,
708 med_rec_t *medrp,
709 md_error_t *ep
710 )
711 {
712 med_handle_t *hp;
713 med_args_t args;
714 med_get_rec_res_t res;
715 int rval = -1;
716 md_set_desc *sd;
717
718 /* initialize */
719 mdclrerror(ep);
720 (void) memset(&args, 0, sizeof (args));
721 (void) memset(&res, 0, sizeof (res));
722
723 /* build args */
724 if ((sd = metaget_setdesc(sp, ep)) == NULL)
725 return (-1);
726
727 if (MD_MNSET_DESC(sd))
728 /*
729 * In the MN diskset, use a generic nodename, multiowner, as
730 * the node initiating the RPC request. This allows
731 * any node to access mediator information.
732 *
733 * MN diskset reconfig cycle forces consistent
734 * view of set/node/drive/mediator information across all nodes
735 * in the MN diskset. This allows the relaxation of
736 * node name checking in rpc.metamedd for MN disksets.
737 *
738 * In the traditional diskset, only a calling node that is
739 * in the mediator record's diskset nodelist can access
740 * mediator data.
741 */
742 args.med.med_caller = Strdup(MED_MN_CALLER);
743 else
744 args.med.med_caller = Strdup(mynode());
745 args.med.med_setname = Strdup(sp->setname);
746 args.med.med_setno = sp->setno;
747
748 /* do it */
749 if ((hp = open_medd_wrap(mdhp, CL_DEF_TMO, ep)) == NULL)
750 return (-1);
751
752 if (med_get_rec_1(&args, &res, hp->clntp) != RPC_SUCCESS)
753 (void) mdrpcerror(ep, hp->clntp, hp->hostname,
754 dgettext(TEXT_DOMAIN, "medd get record"));
755 else
756 (void) meddstealerror(ep, &res.med_status);
757
758 close_medd(hp);
759
760 if (mdisok(ep)) {
761 /* do something with the results */
762 (void) memmove(medrp, &res.med_rec, sizeof (med_rec_t));
763 rval = 0;
764 }
765
766 xdr_free(xdr_med_args_t, (char *)&args);
767 xdr_free(xdr_med_get_rec_res_t, (char *)&res);
768
769 return (rval);
770 }
771
772 /*
773 * Get the name of the host from the mediator daemon.
774 */
775 int
clnt_med_hostname(char * hostname,char ** ret_hostname,md_error_t * ep)776 clnt_med_hostname(
777 char *hostname,
778 char **ret_hostname,
779 md_error_t *ep
780 )
781 {
782 med_handle_t *hp;
783 med_hnm_res_t res;
784 int rval = -1;
785
786 /* initialize */
787 mdclrerror(ep);
788 (void) memset(&res, 0, sizeof (res));
789
790 /* No args */
791
792 /* do it */
793 if ((hp = open_medd(hostname, CL_DEF_TMO, ep)) == NULL)
794 return (-1);
795
796 if (med_hostname_1(NULL, &res, hp->clntp) != RPC_SUCCESS)
797 (void) mdrpcerror(ep, hp->clntp, hostname,
798 dgettext(TEXT_DOMAIN, "medd hostname"));
799 else
800 (void) meddstealerror(ep, &res.med_status);
801
802 close_medd(hp);
803
804 if (mdisok(ep)) {
805 /* do something with the results */
806 rval = 0;
807
808 if (ret_hostname != NULL)
809 *ret_hostname = Strdup(res.med_hnm);
810 }
811
812 xdr_free(xdr_med_hnm_res_t, (char *)&res);
813
814 return (rval);
815 }
816
817 int
meta_med_hnm2ip(md_hi_arr_t * mp,md_error_t * ep)818 meta_med_hnm2ip(md_hi_arr_t *mp, md_error_t *ep)
819 {
820 int i, j;
821 int max_meds;
822
823 if ((max_meds = get_max_meds(ep)) == 0)
824 return (-1);
825
826 for (i = 0; i < max_meds; i++) {
827 mp->n_lst[i].a_flg = 0;
828 /* See if this is the local host */
829 if (mp->n_lst[i].a_cnt > 0 &&
830 strcmp(mp->n_lst[i].a_nm[0], mynode()) == NULL)
831 mp->n_lst[i].a_flg |= NMIP_F_LOCAL;
832
833 for (j = 0; j < mp->n_lst[i].a_cnt; j++) {
834 struct hostent *hp;
835 char *hnm = mp->n_lst[i].a_nm[j];
836
837 /*
838 * Cluster nodename support
839 *
840 * See if the clustering code can give us an IP addr
841 * for the stored name. If not, find it the old way
842 * which will use the public interface.
843 */
844 if (sdssc_get_priv_ipaddr(mp->n_lst[i].a_nm[j],
845 (struct in_addr *)&mp->n_lst[i].a_ip[j]) !=
846 SDSSC_OKAY) {
847 if ((hp = gethostbyname(hnm)) == NULL)
848 return (mdsyserror(ep, EADDRNOTAVAIL,
849 hnm));
850
851 /* We only do INET addresses */
852 if (hp->h_addrtype != AF_INET)
853 return (mdsyserror(ep, EPFNOSUPPORT,
854 hnm));
855
856 /* We take the first address only */
857 if (*hp->h_addr_list) {
858 (void) memmove(&mp->n_lst[i].a_ip[j],
859 *hp->h_addr_list,
860 sizeof (struct in_addr));
861 } else
862 return (mdsyserror(ep, EADDRNOTAVAIL,
863 hnm));
864 }
865
866 }
867 }
868 return (0);
869 }
870
871 int
meta_h2hi(md_h_arr_t * mdhp,md_hi_arr_t * mdhip,md_error_t * ep)872 meta_h2hi(md_h_arr_t *mdhp, md_hi_arr_t *mdhip, md_error_t *ep)
873 {
874 int i, j;
875 int max_meds;
876
877 if ((max_meds = get_max_meds(ep)) == 0)
878 return (-1);
879
880 mdhip->n_cnt = mdhp->n_cnt;
881
882 for (i = 0; i < max_meds; i++) {
883 mdhip->n_lst[i].a_flg = 0;
884 mdhip->n_lst[i].a_cnt = mdhp->n_lst[i].a_cnt;
885 if (mdhp->n_lst[i].a_cnt == 0)
886 continue;
887 for (j = 0; j < mdhp->n_lst[i].a_cnt; j++)
888 (void) strcpy(mdhip->n_lst[i].a_nm[j],
889 mdhp->n_lst[i].a_nm[j]);
890 }
891 return (0);
892 }
893
894 int
meta_hi2h(md_hi_arr_t * mdhip,md_h_arr_t * mdhp,md_error_t * ep)895 meta_hi2h(md_hi_arr_t *mdhip, md_h_arr_t *mdhp, md_error_t *ep)
896 {
897 int i, j;
898 int max_meds;
899
900 if ((max_meds = get_max_meds(ep)) == 0)
901 return (-1);
902
903 mdhp->n_cnt = mdhip->n_cnt;
904 for (i = 0; i < max_meds; i++) {
905 mdhp->n_lst[i].a_cnt = mdhip->n_lst[i].a_cnt;
906 if (mdhip->n_lst[i].a_cnt == 0)
907 continue;
908 for (j = 0; j < mdhip->n_lst[i].a_cnt; j++)
909 (void) strcpy(mdhp->n_lst[i].a_nm[j],
910 mdhip->n_lst[i].a_nm[j]);
911 }
912 return (0);
913 }
914
915 int
setup_med_cfg(mdsetname_t * sp,mddb_config_t * cp,int force,md_error_t * ep)916 setup_med_cfg(
917 mdsetname_t *sp,
918 mddb_config_t *cp,
919 int force,
920 md_error_t *ep
921 )
922 {
923 md_set_desc *sd;
924 int i;
925 int max_meds;
926
927 if (metaislocalset(sp))
928 return (0);
929
930 if ((sd = metaget_setdesc(sp, ep)) == NULL)
931 return (-1);
932
933 if (setup_med_transtab(ep))
934 return (-1);
935
936 if (meta_h2hi(&sd->sd_med, &cp->c_med, ep))
937 return (-1);
938
939 /* Make sure the ip addresses are current */
940 if (meta_med_hnm2ip(&cp->c_med, ep))
941 return (-1);
942
943 if (force)
944 return (0);
945
946 if ((max_meds = get_max_meds(ep)) == 0)
947 return (-1);
948
949 /* Make sure metamedd still running on host - only chk nodename */
950 for (i = 0; i < max_meds; i++) {
951 char *hostname;
952 char *hnm;
953
954 if (sd->sd_med.n_lst[i].a_cnt == 0)
955 continue;
956
957 hnm = sd->sd_med.n_lst[i].a_nm[0];
958
959 if (clnt_med_hostname(hnm, &hostname, ep))
960 return (mddserror(ep, MDE_DS_NOMEDONHOST, sp->setno,
961 hnm, NULL, sp->setname));
962 Free(hostname);
963 }
964 return (0);
965 }
966
967 /*
968 * This is a general routine to get mediator information from
969 * file /etc/lvm/meddb. Commands medstat and metainit use this
970 * routine to get mediator information from all mediator hosts or update
971 * its mediator record respectively.
972 */
973 int
meta_mediator_info_from_file(char * sname,int verbose,md_error_t * ep)974 meta_mediator_info_from_file(char *sname, int verbose, md_error_t *ep)
975 {
976 uint_t c;
977 int i;
978 int j;
979 int fd;
980 int rec_size;
981 char *setname;
982 uint_t setnum;
983 med_rec_t *rec_buf = NULL;
984 med_db_hdr_t *dbhbr;
985 med_rec_t *medrecp;
986 med_data_t medd;
987 med_data_t save_medd;
988 md_h_t mdh;
989 uint_t latest_med_dat_cc = 0;
990 int retval = 0;
991 int medok = 0;
992 int golden = 0;
993 bool_t obandiskset;
994 int isSetFound = 0;
995
996 /* Open the meddb file */
997 if ((fd = open(MED_DB_FILE, O_RDONLY, 0)) == -1) {
998
999 /*
1000 * During the start up of the SVM services, this function
1001 * will be called with an empty sname. In that case it is
1002 * entirely possible for the MED_DB_FILE not to exist.
1003 * If so, then no need to report an error.
1004 */
1005 if (sname != NULL) {
1006 (void) mdsyserror(ep, errno, MED_DB_FILE);
1007 mde_perror(ep, dgettext(TEXT_DOMAIN,
1008 "Error in opening meddb file"));
1009 return (1);
1010 }
1011 return (0);
1012 }
1013
1014 /* Initialize rec_size */
1015 rec_size = roundup(sizeof (med_rec_t), DEV_BSIZE);
1016
1017 /* Allocate a record buffer */
1018 if ((rec_buf = malloc(rec_size)) == NULL) {
1019 (void) mdsyserror(ep, errno, MED_DB_FILE);
1020 mde_perror(ep, dgettext(TEXT_DOMAIN,
1021 "Error in allocating memory"));
1022 goto out;
1023 }
1024
1025 /* read the file header */
1026 if ((read(fd, rec_buf, rec_size)) != rec_size) {
1027 (void) mdsyserror(ep, EINVAL, MED_DB_FILE);
1028 mde_perror(ep, dgettext(TEXT_DOMAIN,
1029 "Error in reading mediator record"));
1030 goto out;
1031 }
1032
1033 dbhbr = (med_db_hdr_t *)rec_buf;
1034
1035 /* Number of records in the mediator file */
1036 c = dbhbr->med_dbh_nm;
1037
1038 for (i = 0; i < c; i++) {
1039 (void) memset(rec_buf, 0, rec_size);
1040
1041 if (read(fd, rec_buf, rec_size) == -1) {
1042 (void) mdsyserror(ep, errno, MED_DB_FILE);
1043 mde_perror(ep, dgettext(TEXT_DOMAIN,
1044 "Error in reading mediator record"));
1045 goto out;
1046 }
1047
1048 medrecp = (med_rec_t *)rec_buf;
1049
1050 /*
1051 * For oban diskset first entry in the rec_nodes field is
1052 * "multiowner" and all other entries are empty.
1053 * Check if this is really multiowner diskset.
1054 */
1055
1056 if ((strcmp(medrecp->med_rec_nodes[0], MED_MN_CALLER) == 0) &&
1057 (medrecp->med_rec_nodes[1][0] == '\0'))
1058 obandiskset = TRUE;
1059 else
1060 obandiskset = FALSE;
1061
1062 if (sname != NULL) {
1063 /*
1064 * Continue if the set name is not in our interest.
1065 * This is required when this routine is called
1066 * from medstat
1067 */
1068
1069 if (strcmp(sname, medrecp->med_rec_snm) != 0) {
1070 continue;
1071 }
1072
1073 if (verbose)
1074 (void) printf("%8.8s\t\t%6.6s\t%6.6s\n",
1075 gettext("Mediator"), gettext("Status"),
1076 gettext("Golden"));
1077
1078 isSetFound = 1;
1079 setname = sname;
1080 } else {
1081 setname = medrecp->med_rec_snm;
1082 }
1083 setnum = medrecp->med_rec_sn;
1084 (void) memset(&medd, '\0', sizeof (medd));
1085 (void) memset(&mdh, '\0', sizeof (mdh));
1086 (void) memset(&save_medd, '\0', sizeof (save_medd));
1087 latest_med_dat_cc = 0;
1088
1089 for (j = 0; j < MED_MAX_HOSTS; j++) {
1090 /*
1091 * It is possible for the n_lst[j] slot to be empty
1092 * if the mediator node has already been removed so
1093 * go to the next slot.
1094 */
1095 if (medrecp->med_rec_meds.n_lst[j].a_cnt == 0)
1096 continue;
1097 mdh = medrecp->med_rec_meds.n_lst[j];
1098
1099 if ((sname != NULL) && (verbose))
1100 (void) printf("%-17.17s\t",
1101 medrecp->med_rec_meds.n_lst[j].a_nm[0]);
1102
1103 if (clnt_user_med_get_data(&mdh, obandiskset,
1104 setname, setnum, &medd, ep) == -1) {
1105 if (sname == NULL) {
1106 continue;
1107 } else {
1108 if (mdanyrpcerror(ep)) {
1109 if (verbose)
1110 (void) printf("%s\n",
1111 gettext("Unreach"
1112 "able"));
1113 continue;
1114 } else if (mdiserror(ep,
1115 MDE_MED_ERROR)) {
1116 if (verbose)
1117 (void) printf("%s\n",
1118 gettext("Bad"));
1119 } else {
1120 if (verbose)
1121 (void) printf("%s\n",
1122 gettext("Fatal"));
1123 }
1124 mde_perror(ep, "");
1125 if (mdiserror(ep, MDE_MED_ERROR))
1126 continue;
1127 goto out;
1128 }
1129 } else {
1130 /*
1131 * Make sure this node has the correct value
1132 * for the mediator record. If not we want the
1133 * highest value from the other nodes. Save it
1134 * for updating once the loop through all the
1135 * mediator nodes has completed.
1136 */
1137 if (sname == NULL) {
1138 if (latest_med_dat_cc <
1139 medd.med_dat_cc) {
1140 latest_med_dat_cc =
1141 medd.med_dat_cc;
1142 (void) memcpy(&save_medd, &medd,
1143 sizeof (medd));
1144 }
1145 } else {
1146 if (verbose)
1147 (void) printf("%s",
1148 gettext("Ok"));
1149 if (medd.med_dat_fl & MED_DFL_GOLDEN) {
1150 if (verbose)
1151 (void) printf("\t%s",
1152 gettext("Yes"));
1153 golden++;
1154 } else {
1155 if (verbose)
1156 (void) printf("\t%s",
1157 gettext("No"));
1158 }
1159 if (verbose)
1160 (void) printf("\n");
1161 medok++;
1162 }
1163 }
1164 }
1165 if (sname == NULL) {
1166
1167 /*
1168 * Mediators only become active when there are
1169 * replica updates to the sets and this can only
1170 * occur when there is a disk in the set.
1171 * If there are no disks found then the save_medd
1172 * structure will be empty. If save_medd is empty,
1173 * do not update the set.
1174 */
1175 if (save_medd.med_dat_sn == 0)
1176 continue;
1177 /*
1178 * Update the latest mediator information
1179 * on this node
1180 */
1181 (void) strlcpy(mdh.a_nm[0], mynode(),
1182 sizeof (mdh.a_nm[0]));
1183 mdh.a_cnt = 1;
1184 if (clnt_user_med_upd_data(&mdh, obandiskset,
1185 setname, setnum, &save_medd, ep) == -1) {
1186 /*
1187 * We had some errors while updaing the
1188 * record. This means this metaset is
1189 * not updated with latest mediator
1190 * information.
1191 */
1192 mde_perror(ep, "");
1193 }
1194
1195 } else {
1196 if (golden) {
1197 retval = 0;
1198 goto out;
1199 }
1200 if (medok < ((medrecp->med_rec_meds.n_cnt / 2) + 1))
1201 retval = 1;
1202 }
1203 }
1204
1205 out:
1206 if ((sname != NULL) && (isSetFound == 0)) {
1207 (void) mderror(ep, MDE_NO_SET, sname);
1208 mde_perror(ep, "");
1209 retval = 1;
1210 }
1211 if (rec_buf != NULL)
1212 Free(rec_buf);
1213 if (close(fd) < 0) {
1214 (void) mdsyserror(ep, errno, MED_DB_FILE);
1215 mde_perror(ep, dgettext(TEXT_DOMAIN,
1216 "Error in closing meddb file"));
1217 return (1);
1218 }
1219 return (retval);
1220 }
1221