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
27 #include <sys/types.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <strings.h>
31 #include <stdlib.h>
32 #include <unistd.h>
33 #include <netdb.h>
34 #include <sys/stream.h>
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <ctype.h>
39 #include <thread.h>
40 #include <pthread.h>
41
42 #include <sys/unistat/spcs_s.h>
43 #include <sys/unistat/spcs_s_u.h>
44 #include <sys/unistat/spcs_s_impl.h>
45 #include <sys/unistat/spcs_errors.h>
46
47 #include <sys/nsctl/rdc_io.h>
48 #include <sys/nsctl/rdc_ioctl.h>
49 #include <sys/nsctl/rdc_prot.h>
50 #include <sys/nsctl/librdc.h>
51 #include <sys/nsctl/rdcrules.h>
52 #include <sys/nsctl/rdcerr.h>
53 #include <sys/nsctl/cfg.h>
54
55 #include <sys/unistat/spcs_dtrinkets.h>
56 #include <sys/unistat/spcs_etrinkets.h>
57
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
61 #include <netinet/tcp.h>
62 #include <rpc/rpc_com.h>
63 #include <rpc/rpc.h>
64
65 struct netbuf svaddr, *svp;
66 struct netconfig nconf, *conf;
67 struct knetconfig knconf;
68
69 /*
70 * libdscfg type stuff here
71 */
72 extern int sv_enable(CFGFILE *cfg, rdcconfig_t *rdc);
73 extern int add_to_rdc_cfg(rdcconfig_t *rdcs);
74 extern int remove_from_rdc_cfg(rdcconfig_t *rdcs);
75 extern int replace_cfgfield(rdcconfig_t *rdcs, char *field, char *value);
76 extern int reverse_in_cfg(rdcconfig_t *rdcs);
77
78 rdcconfig_t *
79 rdc_dup_config(rdcconfig_t *orig)
80 {
81 rdcconfig_t *rc;
82
83 rc = (rdcconfig_t *)calloc(1, sizeof (*rc));
84 if (!rc) {
85 rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
86 return (NULL);
87 }
88
89 *rc = *orig;
90 rc->next = NULL; /* don't want to hook into wrong chaing */
91 return (rc);
92 }
93
94 /*
95 * takes in a chain of rdcconfig_t's and a chain
96 * of rdc_rc_t's, checks for success in the rdc_rc_t,
97 * then adds the corresponding rdcconfig_t to the return
98 * chain.
99 */
100 rdcconfig_t *
101 chain_successful(rdcconfig_t *rdcs, rdc_rc_t *rcs)
102 {
103 rdc_rc_t *rcp;
104 rdcconfig_t *rdcp;
105 rdcconfig_t *ret = NULL;
106 rdcconfig_t *retp = NULL;
107
108 rcp = rcs;
109 rdcp = rdcs;
110
111 while (rcp) {
112 if (rcp->rc == 0) {
113 if ((ret == NULL) && (rdcp->persist)) {
114 retp = ret = rdc_dup_config(rdcp);
115
116 } else if ((ret) && (rdcp->persist)) {
117 retp->next = rdc_dup_config(rdcp);
118 retp = retp->next;
119 }
120 }
121 rcp = rcp->next;
122 rdcp = rdcp->next;
123 }
124 return (ret);
125
126 }
127
128 rdc_set_t
129 config2set(rdcconfig_t *rdc)
130 {
131 rdc_set_t urdc;
132
133 bzero(&urdc, sizeof (rdc_set_t));
134 strncpy(urdc.primary.intf, rdc->phost, MAX_RDC_HOST_SIZE);
135 strncpy(urdc.primary.file, rdc->pfile, NSC_MAXPATH);
136 strncpy(urdc.primary.bitmap, rdc->pbmp, NSC_MAXPATH);
137 strncpy(urdc.secondary.intf, rdc->shost, MAX_RDC_HOST_SIZE);
138 strncpy(urdc.secondary.file, rdc->sfile, NSC_MAXPATH);
139 strncpy(urdc.secondary.bitmap, rdc->sbmp, NSC_MAXPATH);
140 strncpy(urdc.group_name, rdc->group, NSC_MAXPATH);
141
142 return (urdc);
143 }
144
145 rdc_rc_t *
146 new_rc()
147 {
148 rdc_rc_t *rc;
149
150 rc = (rdc_rc_t *)calloc(1, sizeof (*rc));
151 if (rc == NULL) {
152 rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
153 return (NULL);
154 }
155 return (rc);
156 }
157
158 rdc_rc_t
159 rdc_config(rdc_config_t *rdccfg)
160 {
161 rdc_rc_t rc;
162 rdc_set_t *set;
163 spcs_s_info_t ustatus;
164
165 bzero(&rc, sizeof (rc));
166 ustatus = spcs_s_ucreate();
167
168 if (self_check(rdccfg->rdc_set->primary.intf)) {
169 rdccfg->options |= RDC_OPT_PRIMARY;
170 /* this needs changin if we do campus */
171 rdccfg->rdc_set->direct_file[0] = 0;
172 } else {
173 rdccfg->options |= RDC_OPT_SECONDARY;
174 }
175
176 /* set up return stuff.. */
177 set = &rdccfg->rdc_set[0];
178 strncpy(rc.set.phost, set->primary.intf, MAX_RDC_HOST_SIZE);
179 strncpy(rc.set.pfile, set->primary.file, NSC_MAXPATH);
180 strncpy(rc.set.shost, set->secondary.intf, MAX_RDC_HOST_SIZE);
181 strncpy(rc.set.sfile, set->secondary.file, NSC_MAXPATH);
182
183 rc.rc = RDC_IOCTL(RDC_CONFIG, rdccfg, NULL, 0, 0, 0, ustatus);
184
185 if (rc.rc < 0) {
186 rdc_set_error(&ustatus, RDC_SPCS, 0, 0);
187 strncpy(rc.msg, rdc_error(NULL), RDC_ERR_SIZE);
188 }
189
190 return (rc);
191 }
192
193 void *
194 rdc_mtconfig(void *rdc)
195 {
196 rdc_rc_t *rc[1];
197 rdc_set_t *set;
198 spcs_s_info_t ustatus;
199 rdc_config_t *rdccfg = (rdc_config_t *)rdc;
200
201 ustatus = spcs_s_ucreate();
202
203 if (self_check(rdccfg->rdc_set->primary.intf)) {
204 rdccfg->options |= RDC_OPT_PRIMARY;
205 /* this needs changin if we do campus */
206 rdccfg->rdc_set->direct_file[0] = 0;
207 } else {
208 rdccfg->options |= RDC_OPT_SECONDARY;
209 }
210
211 set = &rdccfg->rdc_set[0];
212 *rc = new_rc();
213
214 strncpy(rc[0]->set.phost, set->primary.intf, MAX_RDC_HOST_SIZE);
215 strncpy(rc[0]->set.pfile, set->primary.file, NSC_MAXPATH);
216 strncpy(rc[0]->set.pbmp, set->primary.bitmap, NSC_MAXPATH);
217 strncpy(rc[0]->set.shost, set->secondary.intf, MAX_RDC_HOST_SIZE);
218 strncpy(rc[0]->set.sfile, set->secondary.file, NSC_MAXPATH);
219 strncpy(rc[0]->set.sbmp, set->secondary.bitmap, NSC_MAXPATH);
220
221 rc[0]->rc = RDC_IOCTL(RDC_CONFIG, rdccfg, NULL, 0, 0, 0, ustatus);
222
223 if (rc[0]->rc < 0) {
224 rdc_set_error(&ustatus, RDC_SPCS, 0, 0);
225 strncpy(rc[0]->msg, rdc_error(NULL), RDC_ERR_SIZE);
226 }
227
228 sleep(1); /* give thr_join a chance to be called */
229 free(rdccfg);
230 thr_exit((void **) *rc);
231 return (NULL);
232 }
233 int
234 populate_addrs(rdc_set_t *urdc, int isenable)
235 {
236 struct t_info tinfo;
237 struct hostent *hp;
238 char toname[MAX_RDC_HOST_SIZE];
239 char fromname[MAX_RDC_HOST_SIZE];
240
241 strncpy(fromname, urdc->primary.intf, MAX_RDC_HOST_SIZE);
242 strncpy(toname, urdc->secondary.intf, MAX_RDC_HOST_SIZE);
243
244 if ((fromname[0] == '\0') || (fromname[0] == '\0')) {
245 rdc_set_error(NULL, RDC_INTERNAL, RDC_FATAL,
246 "NULL hostname recieved");
247 return (-1);
248 }
249
250 hp = gethost_byname(fromname);
251 strncpy(fromname, hp->h_name, MAX_RDC_HOST_SIZE);
252 hp = gethost_byname(toname);
253 strncpy(toname, hp->h_name, MAX_RDC_HOST_SIZE);
254
255 if (self_check(fromname) && self_check(toname)) {
256 rdc_set_error(NULL, RDC_INTERNAL, RDC_FATAL, "");
257 }
258
259 if (isenable) {
260 svp = get_addr(toname, RDC_PROGRAM, RDC_VERS_MIN,
261 &conf, NULL, "rdc", &tinfo, 0);
262 if (svp == NULL)
263 return (-1);
264 svaddr = *svp;
265 } else {
266 bzero(&svaddr, sizeof (svaddr));
267 }
268
269 urdc->secondary.addr.len = svaddr.len;
270 urdc->secondary.addr.maxlen = svaddr.maxlen;
271 urdc->secondary.addr.buf = (void*)svaddr.buf;
272
273 if (isenable) {
274 svp = get_addr(fromname, RDC_PROGRAM, RDC_VERS_MIN,
275 &conf, NULL, "rdc", &tinfo, 0);
276 if (svp == NULL)
277 return (-1);
278 svaddr = *svp;
279 } else {
280 bzero(&svaddr, sizeof (svaddr));
281 }
282
283 urdc->primary.addr.len = svaddr.len;
284 urdc->primary.addr.maxlen = svaddr.maxlen;
285 urdc->primary.addr.buf = (void*)svaddr.buf;
286
287 if (isenable) {
288 convert_nconf_to_knconf(conf, &knconf);
289 urdc->netconfig = &knconf;
290 } else {
291 urdc->netconfig = NULL;
292 }
293 urdc->syshostid = (int32_t)gethostid();
294
295 return (1);
296
297 }
298 void
299 rdc_free_config(rdcconfig_t *rdc, int all)
300 {
301 rdcconfig_t *rdcp;
302 rdcconfig_t *rdcq;
303
304 rdcp = rdc;
305 if (all == RDC_FREEONE) {
306 free(rdcp);
307 } else while (rdcp) {
308 rdcq = rdcp->next;
309 free(rdcp);
310 rdcp = rdcq;
311 }
312 rdc = NULL;
313 }
314
315 void
316 rdc_free_rclist(rdc_rc_t *rc)
317 {
318 rdc_rc_t *rcp, *rcq;
319
320 rcp = rc;
321 while (rcp) {
322 rcq = rcp->next;
323 free(rcp);
324 rcp = rcq;
325 }
326
327 }
328 /*ARGSUSED*/
329 rdcconfig_t *
330 rdc_alloc_config(const char *phost, const char *pfile,
331 const char *pbmp, const char *shost, const char *sfile, const char *sbmp,
332 const char *mode, const char *group, const char *ctag, const char *options,
333 int persist)
334 {
335 rdcconfig_t *rc;
336
337 rc = (rdcconfig_t *)calloc(1, sizeof (*rc));
338 if (!rc) {
339 rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
340 return (NULL);
341 }
342 if (phost)
343 strncpy(rc->phost, phost, NSC_MAXPATH);
344 if (pfile)
345 strncpy(rc->pfile, pfile, NSC_MAXPATH);
346 if (pbmp)
347 strncpy(rc->pbmp, pbmp, NSC_MAXPATH);
348 if (shost)
349 strncpy(rc->shost, shost, NSC_MAXPATH);
350 if (sfile)
351 strncpy(rc->sfile, sfile, NSC_MAXPATH);
352 if (sbmp)
353 strncpy(rc->sbmp, sbmp, NSC_MAXPATH);
354
355 strncpy(rc->direct, "ip", 2);
356
357 if (mode)
358 strncpy(rc->mode, mode, NSC_MAXPATH);
359 if (ctag)
360 strncpy(rc->ctag, ctag, NSC_MAXPATH);
361 if (options)
362 strncpy(rc->options, options, NSC_MAXPATH);
363
364 rc->persist = persist;
365 rc->next = NULL;
366
367 return (rc);
368
369 }
370
371 void
372 populate_rc(rdc_rc_t *rcp, rdcconfig_t *rdcp)
373 {
374 rcp->rc = -1;
375 strncpy(rcp->msg, rdc_error(NULL), RDC_ERR_SIZE);
376 strncpy(rcp->set.phost, rdcp->phost, NSC_MAXPATH);
377 strncpy(rcp->set.pfile, rdcp->pfile, NSC_MAXPATH);
378 strncpy(rcp->set.shost, rdcp->shost, NSC_MAXPATH);
379 strncpy(rcp->set.sfile, rdcp->sfile, NSC_MAXPATH);
380 }
381
382 /*
383 * rdc_enable
384 * return values
385 * NULL on error
386 * pointer to rdc_rc_t list of return values
387 */
388 rdc_rc_t *
389 rdc_enable(rdcconfig_t *rdc)
390 {
391 rdc_config_t rdccfg;
392 rdcconfig_t *rdcp = NULL;
393 rdcconfig_t *cfg_rdcs = NULL;
394 rdc_rc_t *rc = NULL;
395 rdc_rc_t *rcp = NULL;
396
397 rdcp = rdc;
398 rc = new_rc();
399 if (!rc) { /* error already set */
400 return (NULL);
401 }
402 rcp = rc;
403 while (rdcp) {
404 if (!rdcp->mode) {
405 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
406 RDC_EINVAL);
407 return (NULL);
408 }
409 bzero(&rdccfg, sizeof (rdc_config_t));
410 rdccfg.rdc_set[0] = config2set(rdcp);
411 rdccfg.command = RDC_CMD_ENABLE;
412 rdccfg.options = RDC_OPT_SETBMP;
413 if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
414 rdccfg.options |= RDC_OPT_SYNC;
415 } else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
416 rdccfg.options |= RDC_OPT_ASYNC;
417 } else {
418 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
419 RDC_EINVAL);
420 return (NULL);
421 }
422
423 populate_addrs(&rdccfg.rdc_set[0], 1);
424
425 if (can_enable(rdcp)) {
426 /* do the operation */
427 *rcp = rdc_config(&rdccfg);
428
429 } else { /* set up what rdc_config would've set up */
430
431 populate_rc(rcp, rdcp);
432
433 }
434 if ((rcp->rc == 0) && (!rdcp->persist)) {
435 /*
436 * if we are not persisting, do this now,
437 * otherwise we will do it when
438 * we have a lock on the cfg in add_to_rdc_cfg
439 */
440 sv_enable(NULL, rdcp);
441 }
442
443 rdcp = rdcp->next;
444 if (!rdcp)
445 break;
446
447 rcp->next = new_rc();
448 rcp = rcp->next;
449 if (!rcp) {
450 /* dont free here, return what you have */
451 break;
452 }
453 }
454
455 /*
456 * travel the rc chain and rdc chain checking results,
457 * building a new chain, and updating dscfg
458 */
459 rcp = rc;
460 rdcp = rdc;
461
462 cfg_rdcs = chain_successful(rdcp, rcp);
463
464 if (add_to_rdc_cfg(cfg_rdcs) < 0) {
465 /* XXX should disable or something here */
466 return (rc);
467 }
468 rdc_free_config(cfg_rdcs, RDC_FREEALL);
469 return (rc);
470
471 }
472
473 rdc_rc_t *
474 rdc_enable_clrbmp(rdcconfig_t *rdc)
475 {
476 rdc_config_t rdccfg;
477 rdcconfig_t *rdcp = NULL;
478 rdcconfig_t *cfg_rdcs = NULL;
479 rdc_rc_t *rc = NULL;
480 rdc_rc_t *rcp = NULL;
481
482 rdcp = rdc;
483 rc = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
484 if (!rc) {
485 rdc_set_error(NULL, RDC_OS, RDC_FATAL, NULL);
486 return (NULL);
487 }
488 rcp = rc;
489 while (rdcp) {
490 if (!rdcp->mode) {
491 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
492 RDC_EINVAL);
493 return (NULL);
494 }
495 bzero(&rdccfg, sizeof (rdc_config_t));
496 rdccfg.rdc_set[0] = config2set(rdcp);
497 rdccfg.command = RDC_CMD_ENABLE;
498 rdccfg.options = RDC_OPT_CLRBMP;
499 if (strncmp(rdcp->mode, "sync", NSC_MAXPATH) == 0) {
500 rdccfg.options |= RDC_OPT_SYNC;
501 } else if (strncmp(rdc->mode, "async", NSC_MAXPATH) == 0) {
502 rdccfg.options |= RDC_OPT_ASYNC;
503 } else {
504 rdc_set_error(NULL, RDC_INTERNAL, RDC_NONFATAL,
505 RDC_EINVAL);
506 return (NULL);
507 }
508
509 populate_addrs(&rdccfg.rdc_set[0], 1);
510
511 if (can_enable(rdcp)) {
512 /* do the operation */
513 *rcp = rdc_config(&rdccfg);
514
515 } else { /* set up what rdc_config would've set up */
516
517 populate_rc(rcp, rdcp);
518
519 }
520 rdcp = rdcp->next;
521 if (!rdcp)
522 break;
523
524 rcp->next = (rdc_rc_t *)calloc(1, sizeof (rdc_rc_t));
525 rcp = rcp->next;
526 if (!rcp)
527 break;
528 }
529
530 /*
531 * travel the rc chain and rdc chain checking results,
532 * building a new chain, and updating dscfg
533 */
534 rcp = rc;
535 rdcp = rdc;
536
537 cfg_rdcs = chain_successful(rdcp, rcp);
538
539 if (add_to_rdc_cfg(cfg_rdcs) < 0) {
540 /* XXX should disable or something here */
541 return (rc);
542 }
543 rdc_free_config(cfg_rdcs, RDC_FREEALL);
544
545 return (rc);
546
547 }
548
549 rdc_rc_t *
550 rdc_disable(rdcconfig_t *rdc)
551 {
552 rdc_config_t rdccfg;
553 rdcconfig_t *rdcp = NULL;
554 rdcconfig_t *cfg_rdcs = NULL;
555 rdc_rc_t *rc = NULL;
556 rdc_rc_t *rcp = NULL;
557
558 rdcp = rdc;
559 rc = new_rc();
560 if (!rc) {
561 return (NULL);
562 }
563 rcp = rc;
564
565 while (rdcp) {
566
567 bzero(&rdccfg, sizeof (rdc_config_t));
568 rdccfg.rdc_set[0] = config2set(rdcp);
569 rdccfg.command = RDC_CMD_DISABLE;
570 populate_addrs(&rdccfg.rdc_set[0], 0);
571
572 *rcp = rdc_config(&rdccfg);
573
574 rdcp = rdcp->next;
575 if (!rdcp)
576 break;
577
578 rcp->next = new_rc();
579 rcp = rcp->next;
580 if (!rcp)
581 return (rc);
582
583 }
584 rcp = rc;
585 rdcp = rdc;
586
587 cfg_rdcs = chain_successful(rdcp, rcp);
588
589 remove_from_rdc_cfg(cfg_rdcs);
590
591 rdc_free_config(cfg_rdcs, RDC_FREEALL);
592
593 return (rc);
594 }
595
596 rdc_rc_t *
597 rdc_log(rdcconfig_t *rdc)
598 {
599 rdc_config_t rdccfg;
600 rdcconfig_t *rdcp = NULL;
601 rdc_rc_t *rc = NULL;
602 rdc_rc_t *rcp = NULL;
603
604 rdcp = rdc;
605 rc = new_rc();
606 if (!rc) {
607 return (NULL);
608 }
609 rcp = rc;
610
611 while (rdcp) {
612 bzero(&rdccfg, sizeof (rdc_config_t));
613 rdccfg.rdc_set[0] = config2set(rdcp);
614 rdccfg.command = RDC_CMD_LOG;
615 populate_addrs(&rdccfg.rdc_set[0], 0);
616
617 *rcp = rdc_config(&rdccfg);
618
619 rdcp = rdcp->next;
620 if (!rdcp)
621 break;
622
623 rcp->next = new_rc();
624 rcp = rcp->next;
625 if (!rcp)
626 break;
627 }
628 return (rc);
629 }
630
631 rdc_rc_t *
632 rdc_usync(rdcconfig_t *rdc)
633 {
634 rdc_config_t *rdccfg;
635 rdcconfig_t *rdcp = NULL;
636 rdc_rc_t *rc = NULL;
637 rdc_rc_t *rcp = NULL;
638 rdc_rc_t *tmprc;
639
640 rdcp = rdc;
641
642 while (rdcp) {
643 /* freed in rdc_mtconfig */
644 rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
645 rdccfg->rdc_set[0] = config2set(rdcp);
646 rdccfg->command = RDC_CMD_COPY;
647 rdccfg->options = RDC_OPT_UPDATE|RDC_OPT_FORWARD;
648 populate_addrs(&rdccfg->rdc_set[0], 0);
649 (void) thr_create(NULL, 0, rdc_mtconfig,
650 (void **) rdccfg, THR_BOUND, NULL);
651 rdcp = rdcp->next;
652 if (!rdcp)
653 break;
654
655 }
656
657 /*
658 * collect status here from thr_join-status,
659 * and add to rdc_rc_t chain ?
660 * this will block, but caller could always thread too
661 */
662 while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
663 if (rc == NULL) {
664 rcp = rc = (rdc_rc_t *)tmprc;
665 } else {
666 rcp->next = (rdc_rc_t *)tmprc;
667 rcp = rcp->next;
668 }
669 }
670
671 return (rc);
672 }
673
674 rdc_rc_t *
675 rdc_fsync(rdcconfig_t *rdc)
676 {
677 rdc_config_t *rdccfg;
678 rdcconfig_t *rdcp = NULL;
679 rdc_rc_t *rc = NULL;
680 rdc_rc_t *rcp = NULL;
681 rdc_rc_t *tmprc = NULL;
682
683 rdcp = rdc;
684 rc = new_rc();
685 if (!rc) {
686 return (NULL);
687 }
688 rcp = rc;
689
690 while (rdcp) {
691 /* freed in rdc_mtconfig */
692 rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
693 rdccfg->rdc_set[0] = config2set(rdcp);
694 rdccfg->command = RDC_CMD_COPY;
695 rdccfg->options = RDC_OPT_FULL|RDC_OPT_FORWARD;
696 populate_addrs(&rdccfg->rdc_set[0], 0);
697 (void) thr_create(NULL, 0, rdc_mtconfig,
698 (void **) rdccfg, THR_BOUND, NULL);
699 rdcp = rdcp->next;
700 if (!rdcp)
701 break;
702
703 }
704
705 /*
706 * collect status here from thr_join-status,
707 * and add to rdc_rc_t chain ?
708 * this will block, but caller could always thread too
709 */
710 while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
711 if (rc == NULL) {
712 rcp = rc = (rdc_rc_t *)tmprc;
713 } else {
714 rcp->next = (rdc_rc_t *)tmprc;
715 rcp = rcp->next;
716 }
717 }
718
719 return (rc);
720 }
721
722 rdc_rc_t *
723 rdc_rsync(rdcconfig_t *rdc)
724 {
725 rdc_config_t *rdccfg;
726 rdcconfig_t *rdcp = NULL;
727 rdc_rc_t *rc = NULL;
728 rdc_rc_t *rcp = NULL;
729 rdc_rc_t *tmprc = NULL;
730
731 rdcp = rdc;
732 rc = new_rc();
733 if (!rc) {
734 return (NULL);
735 }
736 rcp = rc;
737
738 while (rdcp) {
739 tmprc = cant_rsync(rdcp);
740 if (tmprc != NULL) {
741 if (rc == NULL) {
742 rcp = rc = tmprc;
743 } else {
744 rcp->next = tmprc;
745 rcp = rcp->next;
746 }
747 goto next;
748 }
749
750 /* freed in rdc_mtconfig */
751 rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
752 rdccfg->rdc_set[0] = config2set(rdcp);
753 rdccfg->command = RDC_CMD_COPY;
754 rdccfg->options = RDC_OPT_REVERSE|RDC_OPT_FULL;
755 populate_addrs(&rdccfg->rdc_set[0], 0);
756 (void) thr_create(NULL, 0, rdc_mtconfig,
757 (void **) rdccfg, THR_BOUND, NULL);
758 next:
759 rdcp = rdcp->next;
760 if (!rdcp)
761 break;
762 }
763
764 /*
765 * collect status here from thr_join-status,
766 * and add to rdc_rc_t chain ?
767 * this will block, but caller could always thread too
768 */
769 while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
770 if (rc == NULL) {
771 rcp = rc = (rdc_rc_t *)tmprc;
772 } else {
773 rcp->next = (rdc_rc_t *)tmprc;
774 rcp = rcp->next;
775 }
776 }
777
778 return (rc);
779 }
780
781 rdc_rc_t *
782 rdc_ursync(rdcconfig_t *rdc)
783 {
784 rdc_config_t *rdccfg;
785 rdcconfig_t *rdcp = NULL;
786 rdc_rc_t *rc = NULL;
787 rdc_rc_t *rcp = NULL;
788 rdc_rc_t *tmprc = NULL;
789
790 rdcp = rdc;
791
792 while (rdcp) {
793 tmprc = cant_rsync(rdcp);
794 if (tmprc != NULL) {
795 if (rc == NULL) {
796 rcp = rc = tmprc;
797 } else {
798 rcp->next = tmprc;
799 rcp = rcp->next;
800 }
801 goto next;
802 }
803
804 /* freed in rdc_mtconfig */
805 rdccfg = (rdc_config_t *)calloc(1, sizeof (rdc_config_t));
806 rdccfg->rdc_set[0] = config2set(rdcp);
807 rdccfg->command = RDC_CMD_COPY;
808 rdccfg->options = RDC_OPT_REVERSE | RDC_OPT_UPDATE;
809 populate_addrs(&rdccfg->rdc_set[0], 0);
810 (void) thr_create(NULL, 0, rdc_mtconfig,
811 (void **) rdccfg, THR_BOUND, NULL);
812 next:
813 rdcp = rdcp->next;
814 if (!rdcp)
815 break;
816
817 }
818
819 /*
820 * collect status here from thr_join-status,
821 * and add to rdc_rc_t chain ?
822 * this will block, but caller could always thread too
823 */
824 while (thr_join(NULL, NULL, (void**) &tmprc) == 0) {
825 if (rc == NULL) {
826 rcp = rc = (rdc_rc_t *)tmprc;
827 } else {
828 rcp->next = (rdc_rc_t *)tmprc;
829 rcp = rcp->next;
830 }
831 }
832
833 return (rc);
834 }
835
836 rdc_rc_t *
837 rdc_wait(rdcconfig_t *rdc)
838 {
839 rdc_config_t rdccfg;
840 rdcconfig_t *rdcp = NULL;
841 rdc_rc_t *rc = NULL;
842 rdc_rc_t *rcp = NULL;
843
844 rdcp = rdc;
845 rc = new_rc();
846 if (!rc) {
847 return (NULL);
848 }
849 rcp = rc;
850
851 while (rdcp) {
852 bzero(&rdccfg, sizeof (rdc_config_t));
853 rdccfg.rdc_set[0] = config2set(rdcp);
854 rdccfg.command = RDC_CMD_WAIT;
855 populate_addrs(&rdccfg.rdc_set[0], 0);
856
857 *rcp = rdc_config(&rdccfg);
858
859 rdcp = rdcp->next;
860 if (!rdcp)
861 break;
862
863 rcp->next = new_rc();
864 rcp = rcp->next;
865 if (!rcp)
866 break;
867 }
868 return (rc);
869 }
870
871 rdc_rc_t *
872 rdc_set_autosync(rdcconfig_t *rdc, int autosync)
873 {
874 rdc_config_t rdccfg;
875 rdcconfig_t *rdcp = NULL;
876 rdc_rc_t *rc = NULL;
877 rdc_rc_t *rcp = NULL;
878
879 rdcp = rdc;
880 rc = new_rc();
881 if (!rc) {
882 return (NULL);
883 }
884 rcp = rc;
885
886 while (rdcp) {
887 bzero(&rdccfg, sizeof (rdc_config_t));
888 rdccfg.rdc_set[0] = config2set(rdcp);
889 rdccfg.command = RDC_CMD_TUNABLE;
890 rdccfg.rdc_set[0].autosync = autosync;
891 rdccfg.rdc_set[0].maxqitems = -1;
892 rdccfg.rdc_set[0].maxqfbas = -1;
893 populate_addrs(&rdccfg.rdc_set[0], 0);
894
895 *rcp = rdc_config(&rdccfg);
896
897 rdcp = rdcp->next;
898 if (!rdcp)
899 break;
900
901 rcp->next = new_rc();
902 rcp = rcp->next;
903 if (!rcp)
904 break;
905 }
906 return (rc);
907 }
908
909 rdc_rc_t *
910 rdc_set_maxqfbas(rdcconfig_t *rdc, int maxqfbas)
911 {
912 rdc_config_t rdccfg;
913 rdcconfig_t *rdcp = NULL;
914 rdc_rc_t *rc = NULL;
915 rdc_rc_t *rcp = NULL;
916
917 rdcp = rdc;
918 rc = new_rc();
919 if (!rc) {
920 return (NULL);
921 }
922 rcp = rc;
923
924 while (rdcp) {
925 bzero(&rdccfg, sizeof (rdc_config_t));
926 rdccfg.rdc_set[0] = config2set(rdcp);
927 rdccfg.command = RDC_CMD_TUNABLE;
928 rdccfg.rdc_set[0].autosync = -1;
929 rdccfg.rdc_set[0].maxqitems = -1;
930 rdccfg.rdc_set[0].maxqfbas = maxqfbas;
931 populate_addrs(&rdccfg.rdc_set[0], 0);
932
933 *rcp = rdc_config(&rdccfg);
934
935 rdcp = rdcp->next;
936 if (!rdcp)
937 break;
938
939 rcp->next = new_rc();
940 rcp = rcp->next;
941 if (!rcp)
942 break;
943 }
944 return (rc);
945 }
946
947 rdc_rc_t *
948 rdc_set_maxqitems(rdcconfig_t *rdc, int maxqitems)
949 {
950 rdc_config_t rdccfg;
951 rdcconfig_t *rdcp = NULL;
952 rdc_rc_t *rc = NULL;
953 rdc_rc_t *rcp = NULL;
954
955 rdcp = rdc;
956 rc = new_rc();
957
958 if (!rc) {
959 return (NULL);
960 }
961 rcp = rc;
962
963 while (rdcp) {
964 bzero(&rdccfg, sizeof (rdc_config_t));
965 rdccfg.rdc_set[0] = config2set(rdc);
966 rdccfg.command = RDC_CMD_TUNABLE;
967 rdccfg.rdc_set[0].autosync = -1;
968 rdccfg.rdc_set[0].maxqitems = maxqitems;
969 rdccfg.rdc_set[0].maxqfbas = -1;
970 populate_addrs(&rdccfg.rdc_set[0], 0);
971
972 *rcp = rdc_config(&rdccfg);
973
974 rdcp = rdcp->next;
975 if (!rdcp)
976 break;
977
978 rcp->next = new_rc();
979 rcp = rcp->next;
980 if (!rcp)
981 break;
982 }
983 return (rc);
984 }
985
986 rdc_set_t
987 rdc_status(rdcconfig_t *rdc)
988 {
989 rdc_config_t rdccfg;
990
991 bzero(&rdccfg, sizeof (rdc_config_t));
992 rdccfg.rdc_set[0] = config2set(rdc);
993 rdccfg.command = RDC_CMD_STATUS;
994 populate_addrs(&rdccfg.rdc_set[0], 0);
995 rdc_config(&rdccfg);
996
997 return (rdccfg.rdc_set[0]);
998 }
999
1000 int
1001 rdc_get_autosync(rdcconfig_t *rdc)
1002 {
1003 rdc_set_t rdcset;
1004
1005 rdcset = rdc_status(rdc);
1006 return (rdcset.autosync);
1007 }
1008
1009 int
1010 rdc_get_maxqfbas(rdcconfig_t *rdc)
1011 {
1012 rdc_set_t rdcset;
1013
1014 rdcset = rdc_status(rdc);
1015 return (rdcset.maxqfbas);
1016
1017 }
1018
1019 int
1020 rdc_get_maxqitems(rdcconfig_t *rdc)
1021 {
1022 rdc_set_t rdcset;
1023
1024 rdcset = rdc_status(rdc);
1025 return (rdcset.maxqitems);
1026
1027 }
1028
1029 int
1030 set_mode(rdcconfig_t *rdc)
1031 {
1032 if (strcmp(rdc->mode, "async") == 0)
1033 return (RDC_OPT_ASYNC);
1034 else
1035 return (RDC_OPT_SYNC);
1036 }
1037
1038 /*
1039 * reconfig bitmaps are single set only ops
1040 * for obvious reasons
1041 */
1042 rdc_rc_t *
1043 rdc_reconfig_pbmp(rdcconfig_t *rdc, char *pbmp)
1044 {
1045 rdc_config_t rdccfg;
1046 rdc_rc_t *rc;
1047
1048 rc = new_rc();
1049 if ((!rc) || (!pbmp))
1050 return (NULL);
1051
1052 bzero(&rdccfg, sizeof (rdc_config_t));
1053 rdccfg.rdc_set[0] = config2set(rdc);
1054 strncpy(rdccfg.rdc_set[0].primary.bitmap, pbmp, NSC_MAXPATH);
1055 rdccfg.command = RDC_CMD_RECONFIG;
1056 rdccfg.options |= set_mode(rdc);
1057 populate_addrs(&rdccfg.rdc_set[0], 0);
1058
1059 if (can_reconfig_pbmp(rdc, pbmp))
1060 *rc = rdc_config(&rdccfg);
1061 else
1062 populate_rc(rc, rdc);
1063
1064 if ((rc->rc == 0) && (rdc->persist))
1065 if (replace_cfgfield(rdc, "pbitmap", pbmp) < 0) {
1066 rc->rc = -1;
1067 strncpy(rc->msg, rdc_error(NULL), RDC_ERR_SIZE);
1068 }
1069 return (rc);
1070 }
1071
1072 rdc_rc_t *
1073 rdc_reconfig_sbmp(rdcconfig_t *rdc, char *sbmp)
1074 {
1075 rdc_config_t rdccfg;
1076 rdc_rc_t *rc;
1077
1078 rc = new_rc();
1079 if (!rc)
1080 return (NULL);
1081
1082 bzero(&rdccfg, sizeof (rdc_config_t));
1083 rdccfg.rdc_set[0] = config2set(rdc);
1084 strncpy(rdccfg.rdc_set[0].secondary.bitmap, sbmp, NSC_MAXPATH);
1085 rdccfg.command = RDC_CMD_RECONFIG;
1086 rdccfg.options |= set_mode(rdc);
1087 populate_addrs(&rdccfg.rdc_set[0], 0);
1088
1089 if (can_reconfig_sbmp(rdc, sbmp))
1090 *rc = rdc_config(&rdccfg);
1091 else
1092 populate_rc(rc, rdc);
1093
1094 if ((rc->rc == 0) && (rdc->persist))
1095 replace_cfgfield(rdc, "sbitmap", sbmp);
1096
1097 return (rc);
1098 }
1099
1100 rdc_rc_t *
1101 rdc_reconfig_group(rdcconfig_t *rdc, char *group)
1102 {
1103 rdc_config_t rdccfg;
1104 rdcconfig_t *rdcp = NULL;
1105 rdcconfig_t *cfg_rdcs = NULL;
1106 rdc_rc_t *rc = NULL;
1107 rdc_rc_t *rcp = NULL;
1108
1109 rdcp = rdc;
1110 rc = new_rc();
1111 if (!rc) {
1112 return (NULL);
1113 }
1114 rcp = rc;
1115
1116 while (rdcp) {
1117 bzero(&rdccfg, sizeof (rdc_config_t));
1118 /* just in case */
1119 strncpy(rdcp->group, group, NSC_MAXPATH);
1120 rdccfg.rdc_set[0] = config2set(rdcp);
1121 rdccfg.command = RDC_CMD_RECONFIG;
1122 rdccfg.options |= set_mode(rdcp);
1123 populate_addrs(&rdccfg.rdc_set[0], 0);
1124
1125 /* reconfig group rules enforced in kernel */
1126 *rcp = rdc_config(&rdccfg);
1127
1128 rdcp = rdcp->next;
1129 if (!rdcp)
1130 break;
1131
1132 rcp->next = new_rc();
1133 rcp = rcp->next;
1134 if (!rcp)
1135 break;
1136 }
1137 rcp = rc;
1138 rdcp = rdc;
1139 cfg_rdcs = chain_successful(rdcp, rcp);
1140 replace_cfgfield(cfg_rdcs, "group", group);
1141 rdc_free_config(cfg_rdcs, RDC_FREEALL);
1142
1143 return (rc);
1144 }
1145 /*ARGSUSED*/
1146 rdc_rc_t *
1147 rdc_reconfig_ctag(rdcconfig_t *rdc, char *ctag)
1148 {
1149 return (NULL);
1150 }
1151
1152 rdc_rc_t *
1153 rdc_set_sync(rdcconfig_t *rdc)
1154 {
1155 rdc_config_t rdccfg;
1156 rdcconfig_t *rdcp = NULL;
1157 rdcconfig_t *cfg_rdcs = NULL;
1158 rdc_rc_t *rc = NULL;
1159 rdc_rc_t *rcp = NULL;
1160
1161 rdcp = rdc;
1162 rc = new_rc();
1163 if (!rc) {
1164 return (NULL);
1165 }
1166 rcp = rc;
1167
1168 while (rdcp) {
1169 bzero(&rdccfg, sizeof (rdc_config_t));
1170 rdccfg.rdc_set[0] = config2set(rdc);
1171 rdccfg.command = RDC_CMD_RECONFIG;
1172 rdccfg.options |= RDC_OPT_SYNC;
1173 populate_addrs(&rdccfg.rdc_set[0], 0);
1174
1175 *rcp = rdc_config(&rdccfg);
1176
1177 rdcp = rdcp->next;
1178 if (!rdcp)
1179 break;
1180
1181 rcp->next = new_rc();
1182 rcp = rcp->next;
1183 if (!rcp)
1184 break;
1185 }
1186
1187 rcp = rc;
1188 rdcp = rdc;
1189 cfg_rdcs = chain_successful(rdcp, rcp);
1190 replace_cfgfield(cfg_rdcs, "mode", "sync");
1191 rdc_free_config(cfg_rdcs, RDC_FREEALL);
1192
1193 return (rc);
1194 }
1195
1196 rdc_rc_t *
1197 rdc_set_async(rdcconfig_t *rdc)
1198 {
1199 rdc_config_t rdccfg;
1200 rdcconfig_t *rdcp = NULL;
1201 rdcconfig_t *cfg_rdcs = NULL;
1202 rdc_rc_t *rc = NULL;
1203 rdc_rc_t *rcp = NULL;
1204
1205 rdcp = rdc;
1206 rc = new_rc();
1207 if (!rc) {
1208 return (NULL);
1209 }
1210 rcp = rc;
1211
1212 while (rdcp) {
1213 bzero(&rdccfg, sizeof (rdc_config_t));
1214 rdccfg.rdc_set[0] = config2set(rdcp);
1215 rdccfg.command = RDC_CMD_RECONFIG;
1216 rdccfg.options |= RDC_OPT_ASYNC;
1217 populate_addrs(&rdccfg.rdc_set[0], 0);
1218
1219 *rcp = rdc_config(&rdccfg);
1220
1221 rdcp = rdcp->next;
1222 if (!rdcp)
1223 break;
1224
1225 rcp->next = new_rc();
1226 rcp = rcp->next;
1227 if (!rcp)
1228 break;
1229 }
1230 rcp = rc;
1231 rdcp = rdc;
1232 cfg_rdcs = chain_successful(rdcp, rcp);
1233 replace_cfgfield(cfg_rdcs, "mode", "async");
1234 rdc_free_config(cfg_rdcs, RDC_FREEALL);
1235
1236 return (rc);
1237 }
1238
1239 rdc_rc_t *
1240 rdc_health(rdcconfig_t *rdc)
1241 {
1242 rdc_config_t rdccfg;
1243 rdcconfig_t *rdcp = NULL;
1244 rdc_rc_t *rc = NULL;
1245 rdc_rc_t *rcp = NULL;
1246
1247 rdcp = rdc;
1248 rc = new_rc();
1249 if (!rc) {
1250 return (NULL);
1251 }
1252 rcp = rc;
1253
1254 while (rdcp) {
1255 bzero(&rdccfg, sizeof (rdc_config_t));
1256 rdccfg.rdc_set[0] = config2set(rdcp);
1257 rdccfg.command = RDC_CMD_HEALTH;
1258 populate_addrs(&rdccfg.rdc_set[0], 0);
1259
1260 *rcp = rdc_config(&rdccfg);
1261
1262 rdcp = rdcp->next;
1263 if (!rdcp)
1264 break;
1265
1266 rcp->next = new_rc();
1267 rcp = rcp->next;
1268
1269 if (!rcp)
1270 break;
1271
1272 }
1273 return (rc);
1274 }
1275
1276 rdc_rc_t *
1277 rdc_reverse_role(rdcconfig_t *rdc)
1278 {
1279 rdc_config_t rdccfg;
1280 rdcconfig_t *rdcp = NULL;
1281 rdcconfig_t *cfg_rdcs = NULL;
1282 rdc_rc_t *rc = NULL;
1283 rdc_rc_t *rcp = NULL;
1284
1285 rdcp = rdc;
1286 rc = new_rc();
1287 if (!rc) {
1288 return (NULL);
1289 }
1290 rcp = rc;
1291
1292 while (rdcp) {
1293 bzero(&rdccfg, sizeof (rdc_config_t));
1294 rdccfg.rdc_set[0] = config2set(rdcp);
1295 rdccfg.command = RDC_CMD_RECONFIG;
1296 rdccfg.options |= RDC_OPT_REVERSE_ROLE;
1297 rdccfg.options |= set_mode(rdcp);
1298 populate_addrs(&rdccfg.rdc_set[0], 0);
1299
1300 *rcp = rdc_config(&rdccfg);
1301
1302 rdcp = rdcp->next;
1303 if (!rdcp)
1304 break;
1305
1306 rcp->next = new_rc();
1307 rcp = rcp->next;
1308 if (!rcp)
1309 break;
1310 }
1311 rcp = rc;
1312 rdcp = rdc;
1313 cfg_rdcs = chain_successful(rdcp, rcp);
1314 reverse_in_cfg(cfg_rdcs);
1315 rdc_free_config(cfg_rdcs, RDC_FREEALL);
1316
1317 return (rc);
1318 }