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.
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.
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]
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
44 #include <sys/nsctl/rdc_io.h>
45 #include <sys/nsctl/rdc_ioctl.h>
46 #include <sys/nsctl/rdc_prot.h>
48 #include <sys/nsctl/cfg.h>
50 #include <sys/unistat/spcs_s.h>
51 #include <sys/unistat/spcs_s_u.h>
52 #include <sys/unistat/spcs_errors.h>
54 #include <sys/nsctl/librdc.h>
59 #define RDCADM "/usr/sbin/sndradm"
60 #define IIADM "/usr/sbin/iiadm"
62 #define UPDATE "update"
63 #define NOUPDATE "noupdate"
65 #define RESYNC_SLEEP (3 * 60) /* Three minutes */
66 #define MAIN_SLEEP (5 * 60) /* Five minutes */
67 #define CFG_WAIT_SLEEP (5) /* 5 sec */
70 mutex_t cfglock
= DEFAULTMUTEX
;
71 #define LOCKCFG() (void) mutex_lock(&cfglock);
72 #define UNLOCKCFG() (void) mutex_unlock(&cfglock);
74 typedef struct host_list_s
{
75 char *hosts
[MAXHOSTS
];
77 int configured
[MAXHOSTS
];
81 host_list_t
*host_list
;
83 extern char *basename(char *);
87 static int clustered
= 0;
89 int isnewhost(char *host
);
90 void *wait_sync_event();
91 void *wait_link_down(void *host
);
92 void rdc_sync(char *tohost
);
93 void remove_from_hostlist(char *host
);
94 void sync_start(char *master
);
95 void sync_complete(char *master
);
96 void cleanup_hostlist();
97 void group_start(char *group
);
98 void group_complete(char *group
);
104 host_list
= calloc(1, sizeof (host_list_t
));
105 if (host_list
== NULL
) {
106 spcs_log("sndr", NULL
,
107 gettext("host list not initialized, cannot run"));
108 rdc_err(NULL
, gettext("host list not initialized, cannot run"));
110 (void) mutex_init(&host_list
->hosts_mutex
, USYNC_THREAD
, NULL
);
116 sndrsyncd_lintmain(argc
, argv
)
124 rdc_status_t
*rdc_info
;
128 spcs_s_info_t ustatus
;
133 (void) setlocale(LC_ALL
, "");
134 (void) textdomain("rdc");
136 ustatus
= spcs_s_ucreate();
138 program
= basename(argv
[0]);
142 rc
= rdc_check_release(&required
);
145 gettext("unable to determine the current "
146 "Solaris release: %s\n"), strerror(errno
));
148 } else if (rc
== FALSE
) {
150 gettext("incorrect Solaris release (requires %s)\n"),
155 clustered
= cfg_iscluster();
157 rdc_err(NULL
, gettext("unable to ascertain environment"));
160 rdc_maxsets
= rdc_get_maxsets();
161 if (rdc_maxsets
== -1) {
162 spcs_log("sndr", NULL
,
163 gettext("%s: unable to get maxsets value from kernel"),
166 gettext("unable to get maxsets value from kernel"));
168 size
= sizeof (rdc_status_t
) + (sizeof (rdc_set_t
) * (rdc_maxsets
- 1));
169 rdc_info
= malloc(size
);
170 if (rdc_info
== NULL
) {
171 spcs_log("sndr", NULL
,
172 gettext("%s: unable to allocate %ld bytes"),
175 gettext("unable to allocate %ld bytes"), size
);
177 bzero(rdc_info
, size
);
179 rdc_info
->nset
= rdc_maxsets
;
182 * Fork off a child that becomes the daemon.
184 if ((pid
= fork()) > 0)
187 spcs_log("sndr", NULL
,
188 gettext("%s: cannot fork: %s"),
189 program
, strerror(errno
));
190 rdc_err(NULL
, gettext("cannot fork: %s\n"),
195 * In child - become daemon.
198 for (i
= 0; i
< 3; i
++)
201 (void) open("/dev/console", O_WRONLY
|O_APPEND
);
208 (void) setlocale(LC_ALL
, "");
209 (void) textdomain("rdc");
211 /* launch a thread to wait for sync start and sync stop events */
213 if ((trc
= thr_create(NULL
, 0, wait_sync_event
, NULL
,
214 THR_BOUND
|THR_DETACHED
, NULL
)) != 0) {
215 spcs_log("sndr", NULL
,
216 gettext("%s: unable to create thread wait_sync_event"),
219 gettext("%s unable to create thread wait_sync_event"),
223 spcs_log("sndr", NULL
,
224 gettext("%s: thread wait_sync_event started"), program
);
234 (void) sleep(MAIN_SLEEP
);
236 bzero(rdc_info
, size
);
237 rdc_info
->nset
= rdc_maxsets
;
238 if (RDC_IOCTL(RDC_STATUS
, rdc_info
, 0, 0, 0, 0, ustatus
)
240 spcs_log("sndr", &ustatus
,
241 gettext("%s: status ioctl"),
243 rdc_warn(&ustatus
, gettext("status ioctl"));
247 cleanup_hostlist(rdc_info
); /* remove non-existent hosts */
250 * Check all enabled sets to see if a new remote host has
253 for (i
= 0; i
< rdc_maxsets
; i
++) {
254 if (!(rdc_info
->rdc_set
[i
].flags
& RDC_ENABLED
))
256 /* spawn a new thread for each new host found */
257 if (isnewhost(rdc_info
->rdc_set
[i
].secondary
.intf
)) {
259 * right now, we could be here before
260 * the database did the write for this set
261 * I could check the lock on the database
262 * but I am just going to give up some time here
263 * instead. Why do the allocations etc, etc
264 * if the set is enabled in the kernel and not
265 * in the config, we know that this set has the
266 * lock. Why bother adding more contention to
268 * this is a daemon, afterall. its got time
270 (void) sleep(CFG_WAIT_SLEEP
);
272 spcs_log("sndr", NULL
,
273 gettext("%s: new host found (%s) starting "
274 "its autosync thread"), program
,
275 rdc_info
->rdc_set
[i
].secondary
.intf
);
277 trc
= thr_create(NULL
, 0, wait_link_down
,
278 (void *) rdc_info
->rdc_set
[i
].\
279 secondary
.intf
, THR_BOUND
|THR_DETACHED
, NULL
);
282 spcs_log("sndr", NULL
,
284 "%s create new autosync "
285 "thread failed"), program
);
286 rdc_warn(NULL
, gettext(
287 "%s create new autosync "
288 "thread failed"), program
);
298 * The kernel wakes up this function every time it detects the link to the
299 * specified host has dropped.
302 wait_link_down(void *thehost
)
304 char *host
= (char *)thehost
;
305 char tmphost
[MAX_RDC_HOST_SIZE
] = { '\0' };
306 spcs_s_info_t ustatus
;
309 (void) strncpy(tmphost
, host
, MAX_RDC_HOST_SIZE
);
311 ustatus
= spcs_s_ucreate();
316 spcs_log("sndr", NULL
,
317 gettext("%s: awaiting link down ioctl for %s"),
318 program
, host
[0] == '\0' ? tmphost
: host
);
320 if (RDC_IOCTL(RDC_LINK_DOWN
, host
, 0, 0, 0, 0, ustatus
)
322 spcs_log("sndr", &ustatus
,
323 gettext("%s: link down ioctl"),
325 rdc_warn(&ustatus
, gettext("link down ioctl"));
330 spcs_log("sndr", NULL
,
331 gettext("%s: received link down ioctl for %s"),
332 program
, host
[0] == '\0' ? tmphost
: host
);
334 rdc_sync(host
[0] == '\0' ? tmphost
: host
);
341 * Called when the link to the specified host has dropped.
342 * For all Remote Mirror sets using the link that have autosync on,
343 * issue rdcadm -u commands until they complete successfully.
346 rdc_sync(char *tohost
)
348 rdc_set_t
*rdc_set
= NULL
;
349 int *sync_done
= NULL
;
353 rdc_config_t parms
= { 0 };
354 spcs_s_info_t ustatus
;
358 char buf
[CFG_MAX_BUF
];
359 char key
[CFG_MAX_KEY
];
366 ustatus
= spcs_s_ucreate();
368 size
= sizeof (rdc_set_t
) * rdc_maxsets
;
369 rdc_set
= malloc(size
);
370 if (rdc_set
== NULL
) {
371 spcs_log("sndr", NULL
,
372 gettext("%s: unable to allocate %ld bytes"),
375 gettext("unable to allocate %ld bytes"), size
);
378 bzero(rdc_set
, size
);
379 size
= sizeof (int) * rdc_maxsets
;
380 sync_done
= malloc(size
);
381 if (sync_done
== NULL
) {
382 spcs_log("sndr", NULL
,
383 gettext("%s: unable to allocate %ld bytes"),
386 gettext("unable to allocate %ld bytes"), size
);
389 bzero(sync_done
, size
);
392 * Get all sndr entries with shost matching tohost, and save the
393 * details in an array.
395 for (i
= 0; i
< rdc_maxsets
; i
++) {
397 bzero(buf
, sizeof (buf
));
398 bzero(key
, sizeof (key
));
400 (void) snprintf(key
, sizeof (key
), "sndr.set%d.shost",
405 if ((cfg
= cfg_open(NULL
)) == NULL
) {
406 spcs_log("sndr", NULL
,
407 gettext("%s: error opening config"),
411 gettext("error opening config"));
416 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
417 spcs_log("sndr", NULL
,
418 gettext("%s: error locking config"),
420 rdc_warn(NULL
, gettext("error locking config"));
427 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
428 if (numfound
== 0) /* no matching hosts */
429 death
= 1; /* thread will exit */
432 if (strcmp(buf
, tohost
) != 0)
436 (void) strncpy(rdc_set
[sets
].secondary
.intf
, buf
,
439 /* Got a matching entry */
441 (void) snprintf(key
, sizeof (key
), "sndr.set%d.phost",
443 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
445 (void) strncpy(rdc_set
[sets
].primary
.intf
, buf
,
448 (void) snprintf(key
, sizeof (key
), "sndr.set%d.primary",
450 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
452 (void) strncpy(rdc_set
[sets
].primary
.file
, buf
, NSC_MAXPATH
);
454 (void) snprintf(key
, sizeof (key
), "sndr.set%d.secondary",
456 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
458 (void) strncpy(rdc_set
[sets
].secondary
.file
, buf
, NSC_MAXPATH
);
460 parms
.command
= RDC_CMD_STATUS
;
461 bcopy((void *)(&rdc_set
[sets
]), (void *)(&parms
.rdc_set
[0]),
465 * release cfg before diving into the kernel
466 * this prevents a possible deadlock when doing
467 * a reverse sync whick will wake up the sync_event
468 * thread which will try and iiadm -c and hang
469 * because we still have the cfg_lock. the timed
470 * wait cv in the kernel will fail the sync and things
479 if (RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0, ustatus
) < 0) {
482 if ((parms
.rdc_set
[0].autosync
== 0) ||
483 (!(parms
.rdc_set
[0].flags
& RDC_LOGGING
))) {
487 /* Found a suitable set with autosync on, in logging mode */
499 spcs_log("sndr", NULL
,
500 gettext("%s: no sets requiring autosync found for %s"),
504 spcs_log("sndr", NULL
,
505 gettext("%s: autosync thread stopping for %s "
506 "(host deconfigured)"), program
, tohost
);
511 /* Keep issuing rdcadm -u commands until they have all completed */
516 (void) sleep(RESYNC_SLEEP
);
518 /* Issue rdcadm -u commands for all remaining sets */
519 for (i
= 0; i
< sets
; i
++) {
524 * Need to check if autosync was turned off for a set
525 * while we were sleeping. We could have the case where
526 * an update sync failed and autosync was disabled
527 * while we were sleeping and didn't detect the disable.
530 parms
.command
= RDC_CMD_STATUS
;
531 bcopy((void *)(&rdc_set
[i
]),
532 (void *)(&parms
.rdc_set
[0]), sizeof (rdc_set_t
));
533 if (RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0,
535 spcs_log("sndr", &ustatus
, gettext("%s: "
536 "status not available for %s:%s, stopping "
537 "this autosync attempt"), program
, tohost
,
538 rdc_set
[i
].secondary
.file
);
543 if (!(parms
.rdc_set
[0].autosync
)) {
545 spcs_log("sndr", NULL
, gettext("%s: autosync disabled during sleep, "
546 "stopping attempt for set %s:%s"), program
, tohost
,
547 rdc_set
[i
].secondary
.file
);
554 (void) sprintf(cmd
, "%s -un %s:%s", RDCADM
, tohost
,
555 rdc_set
[i
].secondary
.file
);
556 spcs_log("sndr", NULL
,
557 gettext("%s: issuing update sync for %s:%s"),
558 program
, tohost
, rdc_set
[i
].secondary
.file
);
562 /* Issue rdcadm -w commands to wait for updates to finish */
563 for (i
= 0; i
< sets
; i
++) {
567 (void) sprintf(cmd
, "%s -wn %s:%s", RDCADM
, tohost
,
568 rdc_set
[i
].secondary
.file
);
569 spcs_log("sndr", NULL
,
570 gettext("%s: issuing wait for %s:%s"),
571 program
, tohost
, rdc_set
[i
].secondary
.file
);
575 parms
.command
= RDC_CMD_STATUS
;
576 bcopy((void *)(&rdc_set
[i
]),
577 (void *)(&parms
.rdc_set
[0]), sizeof (rdc_set_t
));
579 if (RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0,
581 spcs_log("sndr", &ustatus
,
582 gettext("%s: status not available for "
583 "%s:%s, stopping this autosync attempt"),
584 program
, tohost
, rdc_set
[i
].secondary
.file
);
589 /* Check if completed OK, failed or autosync off */
590 if (!(parms
.rdc_set
[0].autosync
) ||
591 !(parms
.rdc_set
[0].flags
& RDC_LOGGING
) &&
592 !(parms
.rdc_set
[0].flags
& RDC_SYNCING
)) {
598 if (syncs_done
== sets
)
599 break; /* All completed OK */
607 spcs_s_ufree(&ustatus
);
612 if (death
) { /* bye bye */
614 * if perhaps we lost some race, lets remove this entry from
615 * the list. Then, if something did go wrong, and we did kill
616 * a valid thread, it will be detected on the next go around
617 * of the thread who is looking for new hosts to spawn threads
620 remove_from_hostlist(tohost
);
624 (void) sleep(RESYNC_SLEEP
);
628 * Wait for notification by the kernel of a sync start or a sync completed OK
633 spcs_s_info_t ustatus
;
634 char master
[NSC_MAXPATH
];
635 char group
[NSC_MAXPATH
];
638 ustatus
= spcs_s_ucreate();
645 /* Kernel tells us which volume and group the event is for */
646 state
= RDC_IOCTL(RDC_SYNC_EVENT
, master
, group
, 0, 0, 0,
648 if (state
< SPCS_S_OK
) {
649 if (errno
!= EAGAIN
) {
650 spcs_log("sndr", &ustatus
,
651 gettext("%s: update ioctl"),
653 rdc_warn(&ustatus
, gettext("update ioctl"));
661 * If target is mounted at the start of a sync or reverse sync,
662 * return a negative ack.
664 if ((state
== RDC_SYNC_START
|| state
== RDC_RSYNC_START
) &&
666 spcs_log("sndr", NULL
,
667 gettext("%s: %s has a file system mounted"),
670 gettext("%s has a file system mounted"),
672 master
[0] = '\0'; /* negative ack */
686 group_complete(group
);
688 sync_complete(master
);
700 * A sync has completed OK to a volume not belonging to a group.
701 * Set the state of the ndr_ii config entry to "update".
704 sync_complete(char *master
)
707 char buf
[CFG_MAX_BUF
];
708 char key
[CFG_MAX_KEY
];
714 if ((cfg
= cfg_open(NULL
)) == NULL
) {
715 spcs_log("sndr", NULL
,
716 gettext("%s: error opening config"),
718 rdc_warn(NULL
, gettext("error opening config"));
722 if (!cfg_lock(cfg
, CFG_WRLOCK
)) {
723 spcs_log("sndr", NULL
,
724 gettext("%s: error locking config"),
726 rdc_warn(NULL
, gettext("error locking config"));
732 /* get ndr_ii entries until a match is found */
736 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.secondary",
738 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
740 if (strcmp(buf
, master
) != 0)
743 /* Found the matching entry */
746 * Set state to "update" so that starting another sync will
747 * cause a new Point-in-Time Copy snapshot to be taken.
749 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.state",
751 if ((cfg_put_cstring(cfg
, key
, UPDATE
, strlen(UPDATE
)) < 0) ||
752 (cfg_commit(cfg
) < 0)) {
753 spcs_log("sndr", NULL
,
754 gettext("%s: unable to update \"%s\" "
755 "in configuration storage: %s"),
756 program
, buf
, cfg_error(&sev
));
758 gettext("unable to update \"%s\" "
759 "in configuration storage: %s"),
760 buf
, cfg_error(&sev
));
771 * Starting a sync to the specified master volume.
772 * Check the ndr_ii config entries to see if a Point-in-Time Copy
773 * snapshot should be taken.
776 sync_start(char *master
)
779 char buf
[CFG_MAX_BUF
];
780 char key
[CFG_MAX_KEY
];
786 char shadow
[NSC_MAXPATH
];
787 char bitmap
[NSC_MAXPATH
];
791 if ((cfg
= cfg_open(NULL
)) == NULL
) {
792 spcs_log("sndr", NULL
,
793 gettext("%s: error opening config"),
796 gettext("error opening config"));
800 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
801 spcs_log("sndr", NULL
,
802 gettext("%s: error locking config"),
804 rdc_warn(NULL
, gettext("error locking config"));
811 /* get ndr_ii entries until a match is found */
815 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.secondary",
817 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
819 if (strcmp(buf
, master
) != 0)
822 /* Got a matching entry */
824 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.shadow",
826 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
828 (void) strncpy(shadow
, buf
, NSC_MAXPATH
);
830 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.bitmap",
832 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
834 (void) strncpy(bitmap
, buf
, NSC_MAXPATH
);
836 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.state",
838 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
842 * If an PIT snapshot has already been taken, and syncing did
843 * not complete, the state will be "noupdate", to indicate we
844 * should not take another one at this point.
846 if (strcmp(buf
, NOUPDATE
) != 0)
859 /* get ii entries until a match is found */
863 (void) snprintf(key
, sizeof (key
), "ii.set%d.shadow",
865 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
867 if (strcmp(buf
, shadow
) != 0)
870 /* Matching shadow found, so ii already enabled */
876 /* Already PIT enabled, so just take a snapshot */
878 /* Get cluster tag of matching entry */
879 (void) snprintf(key
, sizeof (key
), "ii.set%d.cnode", setnumber
);
880 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) >= 0)
881 if ((strlen(buf
) == 0) || (buf
[0] == '-'))
885 (void) sprintf(cmd
, "%s %s -u s %s", IIADM
, ctag
, shadow
);
888 * If clustered, need to enable PIT Copy sets in the same
889 * cluster as the Remote Mirror set
893 /* Find a RM set with master as the local volume */
895 for (i
= 0; i
< rdc_maxsets
; i
++) {
897 (void) snprintf(key
, sizeof (key
),
898 "sndr.set%d.phost", setnumber
);
899 if (cfg_get_cstring(cfg
, key
, buf
,
904 (void) snprintf(key
, sizeof (key
),
905 "sndr.set%d.primary", setnumber
);
907 (void) snprintf(key
, sizeof (key
),
908 "sndr.set%d.secondary", setnumber
);
909 if (cfg_get_cstring(cfg
, key
, buf
,
913 if (strcmp(buf
, master
) != 0)
916 /* Get cluster tag of matching entry */
918 (void) snprintf(key
, sizeof (key
),
919 "sndr.set%d.cnode", setnumber
);
920 if (cfg_get_cstring(cfg
, key
, buf
,
923 if ((strlen(buf
) == 0) || (buf
[0] == '-'))
924 ctag
= strdup("local");
931 /* Not already enabled, so enable a dependent */
933 (void) sprintf(cmd
, "%s -C %s -e dep %s %s %s", IIADM
,
934 ctag
, master
, shadow
, bitmap
);
937 (void) sprintf(cmd
, "%s -e dep %s %s %s", IIADM
, master
,
943 if (system(cmd
) != 0) {
944 spcs_log("sndr", NULL
,
945 gettext("Point-in-Time Copy snapshot failed for %s %s %s."
946 " Please check validity of ndr_ii entry"),
947 master
, shadow
, bitmap
);
954 * PIT Copy enable or update was fine, so update the ndr_ii entry
955 * to "noupdate", to prevent invalid point in time copies.
958 if ((cfg
= cfg_open(NULL
)) == NULL
) {
959 spcs_log("sndr", NULL
,
960 gettext("%s: error opening config"),
963 gettext("error opening config"));
967 if (!cfg_lock(cfg
, CFG_WRLOCK
)) {
968 spcs_log("sndr", NULL
,
969 gettext("%s: error locking config"),
971 rdc_warn(NULL
, gettext("error locking config"));
977 /* get ndr_ii entries until a match is found */
981 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.shadow",
983 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
985 if (strcmp(buf
, shadow
) != 0)
988 /* Found the matching entry */
990 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.state",
992 if ((cfg_put_cstring(cfg
, key
, NOUPDATE
,
993 strlen(NOUPDATE
)) < 0) || (cfg_commit(cfg
) < 0)) {
994 spcs_log("sndr", NULL
,
995 gettext("%s: unable to update \"%s\" "
996 "in configuration storage: %s"),
997 program
, buf
, cfg_error(&sev
));
999 gettext("unable to update \"%s\" "
1000 "in configuration storage: %s"),
1001 buf
, cfg_error(&sev
));
1010 cleanup_hostlist(rdc_status_t
*rdc_info
)
1013 char *host
, *exhost
;
1016 (void) mutex_lock(&host_list
->hosts_mutex
);
1017 for (i
= 0; i
< host_list
->numhosts
; i
++) {
1019 for (j
= 0; (j
< rdc_maxsets
) && !found
; j
++) {
1020 if (!rdc_info
->rdc_set
[j
].flags
& RDC_ENABLED
)
1022 if ((!host_list
->configured
[i
]) ||
1023 (host_list
->hosts
[i
] == '\0')) {
1024 (void) mutex_unlock(&host_list
->hosts_mutex
);
1028 host
= rdc_info
->rdc_set
[j
].secondary
.intf
;
1029 if (strcmp(host_list
->hosts
[i
], host
) == 0)
1032 if (j
== rdc_maxsets
) {
1034 * this set is not in the kernel, so remove from list
1036 exhost
= host_list
->hosts
[i
];
1043 while (k
< host_list
->numhosts
) {
1044 host_list
->hosts
[k
] = k
< host_list
->numhosts
- 1 ?
1045 host_list
->hosts
[k
+1] : NULL
;
1048 host_list
->numhosts
--;
1050 bcopy(&host_list
->configured
[i
+1],
1051 &host_list
->configured
[i
],
1052 (MAXHOSTS
- i
+ 1) * sizeof (int));
1053 host_list
->configured
[MAXHOSTS
- 1] = 0;
1056 (void) mutex_unlock(&host_list
->hosts_mutex
);
1060 * explicity remove a host from the host list
1061 * also update the configured array
1062 * called in rdc_sync, just before exiting a thread.
1065 remove_from_hostlist(char *host
)
1071 if ((!host
) || (host
[0] == '\0'))
1074 (void) mutex_lock(&host_list
->hosts_mutex
);
1075 for (i
= 0; i
< host_list
->numhosts
; i
++) {
1076 if (strcmp(host
, host_list
->hosts
[i
]) == 0) { /* found it */
1077 exhost
= host_list
->hosts
[i
];
1083 while (k
< host_list
->numhosts
) {
1084 host_list
->hosts
[k
] = k
< host_list
->numhosts
- 1 ?
1085 host_list
->hosts
[k
+1] : NULL
;
1088 host_list
->numhosts
--;
1089 bcopy(&host_list
->configured
[i
+1],
1090 &host_list
->configured
[i
],
1091 (MAXHOSTS
- i
+ 1) * sizeof (int));
1092 host_list
->configured
[MAXHOSTS
- 1] = 0;
1096 (void) mutex_unlock(&host_list
->hosts_mutex
);
1099 * Check to see if this host isn't in our list, so needs a new rdcsyncd proc
1102 isnewhost(char *host
)
1107 if (self_check(host
)) {
1111 (void) mutex_lock(&host_list
->hosts_mutex
);
1113 for (i
= 0; i
< MAXHOSTS
; i
++) {
1114 if (host_list
->configured
[i
] == 0) {
1115 host_list
->configured
[i
] = 1;
1116 host_list
->hosts
[i
] = strdup(host
);
1117 host_list
->numhosts
++;
1120 if (strcmp(host
, host_list
->hosts
[i
]) == 0) {
1125 (void) mutex_unlock(&host_list
->hosts_mutex
);
1133 * Look for a matching volume name in our remembered list.
1136 volume_match(char *buf
, char **volume_list
, int volumes
)
1141 for (i
= 0; i
< volumes
; i
++) {
1142 vol
= volume_list
[i
];
1143 if (strcmp(buf
, vol
) == 0) {
1152 * A sync has completed to a group. We can only update the ndr_ii entries
1153 * if all the members of the group have completed their syncs OK.
1154 * It would be bad to allow some members of the group to have PIT Copy snapshots
1155 * taken and others not, as they need to be consistent.
1158 group_complete(char *group
)
1160 char **volumes
= NULL
;
1161 spcs_s_info_t ustatus
;
1162 rdc_config_t parms
= { 0 };
1163 char buf
[CFG_MAX_BUF
];
1164 char key
[CFG_MAX_KEY
];
1165 CFGFILE
*cfg
= NULL
;
1169 int replicating
= 0;
1170 char primary
[NSC_MAXPATH
];
1171 char secondary
[NSC_MAXPATH
];
1172 char phost
[MAX_RDC_HOST_SIZE
];
1173 char shost
[MAX_RDC_HOST_SIZE
];
1179 ustatus
= spcs_s_ucreate();
1181 size
= sizeof (char *) * rdc_maxsets
;
1182 volumes
= malloc(size
);
1183 if (volumes
== NULL
) {
1184 spcs_log("sndr", NULL
,
1185 gettext("%s: unable to allocate %ld bytes"),
1188 gettext("unable to allocate %ld bytes"), size
);
1191 bzero(volumes
, size
);
1194 * If all members of this group are replicating
1195 * set ii_ndr state to "update". Otherwise leave them alone.
1198 if ((cfg
= cfg_open(NULL
)) == NULL
) {
1199 spcs_log("sndr", NULL
,
1200 gettext("%s: error opening lconfig"),
1202 rdc_warn(NULL
, gettext("error opening config"));
1207 if (!cfg_lock(cfg
, CFG_RDLOCK
)) {
1208 spcs_log("sndr", NULL
,
1209 gettext("%s: error locking config"),
1211 rdc_warn(NULL
, gettext("error locking config"));
1217 /* get all RM entries, with a matching group, that are replicating */
1218 for (i
= 0; i
< rdc_maxsets
; i
++) {
1221 (void) snprintf(key
, sizeof (key
),
1222 "sndr.set%d.group", setnumber
);
1223 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
1226 if (strcmp(buf
, group
) != 0)
1229 /* Found a matching entry */
1231 (void) snprintf(key
, sizeof (key
),
1232 "sndr.set%d.primary", setnumber
);
1233 if (cfg_get_cstring(cfg
, key
, primary
, sizeof (primary
)) < 0)
1235 (void) strcpy(parms
.rdc_set
->primary
.file
, primary
);
1237 (void) snprintf(key
, sizeof (key
),
1238 "sndr.set%d.phost", setnumber
);
1239 if (cfg_get_cstring(cfg
, key
, phost
, sizeof (phost
)) < 0)
1241 (void) strcpy(parms
.rdc_set
->primary
.intf
, phost
);
1243 (void) snprintf(key
, sizeof (key
),
1244 "sndr.set%d.secondary", setnumber
);
1245 if (cfg_get_cstring(cfg
, key
, secondary
,
1246 sizeof (secondary
)) < 0)
1248 (void) strcpy(parms
.rdc_set
->secondary
.file
, secondary
);
1250 (void) snprintf(key
, sizeof (key
),
1251 "sndr.set%d.shost", setnumber
);
1252 if (cfg_get_cstring(cfg
, key
, shost
, sizeof (shost
)) < 0)
1254 (void) strcpy(parms
.rdc_set
->secondary
.intf
, shost
);
1256 parms
.command
= RDC_CMD_STATUS
;
1257 if (RDC_IOCTL(RDC_CONFIG
, &parms
, NULL
, 0, 0, 0, ustatus
) < 0) {
1261 /* We found a matching set */
1264 if (self_check(phost
))
1265 local_file
= primary
;
1267 local_file
= secondary
;
1269 rdc_set
= &parms
.rdc_set
[0];
1270 if (!(rdc_set
->flags
& RDC_LOGGING
) &&
1271 !(rdc_set
->flags
& RDC_SYNCING
)) {
1272 volumes
[replicating
] = strdup(local_file
);
1273 if (volumes
[replicating
] == NULL
) {
1274 size
= strlen(local_file
);
1275 spcs_log("sndr", NULL
,
1276 gettext("%s: unable to allocate %ld bytes"),
1279 gettext("unable to allocate %ld bytes"),
1283 /* We remember all replicating sets */
1286 break; /* Not all replicating, so done */
1289 if (found
!= replicating
)
1292 /* All replicating, so update ndr_ii state fields */
1296 if (!cfg_lock(cfg
, CFG_WRLOCK
)) {
1297 spcs_log("sndr", NULL
,
1298 gettext("%s: error locking lconfig"),
1300 rdc_warn(NULL
, gettext("error locking config"));
1305 * Search through the ndr_ii entries for entries
1306 * that match the saved secondary volume names.
1307 * Set state to "update".
1310 for (i
= 0; ; i
++) {
1313 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.secondary",
1315 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
1318 if (!volume_match(buf
, volumes
, found
)) {
1322 /* Got a matching entry */
1324 (void) snprintf(key
, sizeof (key
),
1325 "ndr_ii.set%d.state", setnumber
);
1326 if ((cfg_put_cstring(cfg
, key
, UPDATE
, strlen(UPDATE
)) < 0) ||
1327 (cfg_commit(cfg
) < 0)) {
1328 spcs_log("sndr", NULL
,
1329 gettext("%s: unable to update \"%s\" "
1330 "in configuration storage: %s"),
1331 program
, buf
, cfg_error(&sev
));
1333 gettext("unable to update \"%s\" "
1334 "in configuration storage: %s"),
1335 buf
, cfg_error(&sev
));
1345 spcs_s_ufree(&ustatus
);
1347 for (i
= 0; i
< replicating
; i
++)
1355 * Sync started to a member of a group.
1356 * If all members of the group are in ndr_ii state "update" then take an PIT
1357 * snapshot on all of them. This will provide a consistent point-in-time
1358 * copy until whatever syncs take place are all completed.
1361 group_start(char *group
)
1363 char **masters
= NULL
;
1364 char **shadows
= NULL
;
1365 char **bitmaps
= NULL
;
1367 char buf
[CFG_MAX_BUF
];
1368 char key
[CFG_MAX_KEY
];
1369 CFGFILE
*cfg
= NULL
;
1375 int update_needed
= 0;
1381 size
= sizeof (char *) * rdc_maxsets
;
1382 masters
= malloc(size
);
1383 if (masters
== NULL
) {
1384 spcs_log("sndr", NULL
,
1385 gettext("%s: unable to allocate %ld bytes"),
1388 gettext("unable to allocate %ld bytes"), size
);
1391 bzero(masters
, size
);
1392 shadows
= malloc(size
);
1393 if (shadows
== NULL
) {
1394 spcs_log("sndr", NULL
,
1395 gettext("%s: unable to allocate %ld bytes"),
1398 gettext("unable to allocate %ld bytes"), size
);
1401 bzero(shadows
, size
);
1402 bitmaps
= malloc(size
);
1403 if (bitmaps
== NULL
) {
1404 spcs_log("sndr", NULL
,
1405 gettext("%s: unable to allocate %ld bytes"),
1408 gettext("unable to allocate %ld bytes"), size
);
1411 bzero(bitmaps
, size
);
1414 if ((cfg
= cfg_open(NULL
)) == NULL
) {
1415 spcs_log("sndr", NULL
,
1416 gettext("%s: error opening config"),
1419 gettext("error opening config"));
1424 if (!cfg_lock(cfg
, CFG_WRLOCK
)) {
1425 spcs_log("sndr", NULL
,
1426 gettext("%s: error locking config"),
1428 rdc_warn(NULL
, gettext("error locking config"));
1432 /* Now get all Remote Mirror entries with a matching group */
1433 for (i
= 0; i
< rdc_maxsets
; i
++) {
1436 (void) snprintf(key
, sizeof (key
),
1437 "sndr.set%d.group", setnumber
);
1438 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
1441 if (strcmp(buf
, group
) != 0)
1444 /* Found a matching entry */
1446 (void) snprintf(key
, sizeof (key
),
1447 "sndr.set%d.phost", setnumber
);
1448 if (cfg_get_cstring(cfg
, key
, buf
, sizeof (buf
)) < 0)
1451 if (self_check(buf
)) {
1452 (void) snprintf(key
, sizeof (key
), "sndr.set%d.primary",
1455 (void) snprintf(key
, sizeof (key
),
1456 "sndr.set%d.secondary", setnumber
);
1458 if (cfg_get_cstring(cfg
, key
, buf
, sizeof (buf
)) < 0)
1461 masters
[sndr_sets
] = strdup(buf
);
1462 if (masters
[sndr_sets
] == NULL
) {
1464 spcs_log("sndr", NULL
,
1465 gettext("%s: unable to allocate %ld bytes"),
1468 gettext("unable to allocate %ld bytes"), size
);
1473 if (ctag
== NULL
&& clustered
) {
1474 /* Get cluster tag of matching entry */
1476 (void) snprintf(key
, sizeof (key
), "sndr.set%d.cnode",
1478 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) >= 0)
1484 * Search through the ndr_ii entries for entries
1485 * that match the saved local volume names and are in "update" state.
1490 for (i
= 0; ; i
++) {
1493 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.secondary",
1495 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
1498 if (!volume_match(buf
, masters
, sndr_sets
))
1501 /* Got a matching entry */
1503 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.shadow",
1505 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
1507 shadows
[update_needed
] = strdup(buf
);
1508 if (shadows
[update_needed
] == NULL
) {
1510 spcs_log("sndr", NULL
,
1511 gettext("%s: unable to allocate %ld bytes"),
1514 gettext("unable to allocate %ld bytes"), size
);
1518 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.bitmap",
1520 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
1523 bitmaps
[update_needed
] = strdup(buf
);
1524 if (bitmaps
[update_needed
] == NULL
) {
1526 spcs_log("sndr", NULL
,
1527 gettext("%s: unable to allocate %ld bytes"),
1530 gettext("unable to allocate %ld bytes"), size
);
1534 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.state",
1536 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0) {
1539 if (strcmp(buf
, UPDATE
) != 0) {
1546 if (update_needed
!= sndr_sets
) {
1548 spcs_log("sndr", NULL
,
1549 gettext("%s: group sync: no Point-in-Time Copy snapshot "
1550 "for %s"), program
, group
);
1555 /* All RM sets in the group have an ndr_ii entry in "update" state */
1557 /* Issue PIT Copy snapshot commands for all sets in the group */
1558 for (j
= 0; j
< sndr_sets
; j
++) {
1561 /* get ii entries until a match is found */
1562 for (i
= 0; ; i
++) {
1565 (void) snprintf(key
, sizeof (key
), "ii.set%d.shadow",
1567 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
1569 if (strcmp(buf
, shadows
[j
]) != 0)
1572 /* Matching shadow found, so ii already enabled */
1578 if (cfg_commit(cfg
) < 0)
1579 rdc_warn(NULL
, gettext("commit config error"));
1583 (void) sprintf(cmd
, "%s -u s %s", IIADM
, shadows
[j
]);
1586 (void) sprintf(cmd
, "%s -C %s -e dep %s %s %s",
1587 IIADM
, ctag
, masters
[j
], shadows
[j
],
1592 (void) sprintf(cmd
, "%s -e dep %s %s %s", IIADM
,
1593 masters
[j
], shadows
[j
], bitmaps
[j
]);
1596 if (system(cmd
) != 0) {
1597 spcs_log("sndr", NULL
,
1598 gettext("%s: group sync: Point-in-Time Copy"
1599 " snapshot failed for %s"),
1600 program
, masters
[j
]);
1605 if ((cfg
= cfg_open(NULL
)) == NULL
) {
1606 spcs_log("sndr", NULL
,
1607 gettext("%s: error opening config"),
1610 gettext("error opening config"));
1613 if (!cfg_lock(cfg
, CFG_WRLOCK
)) {
1614 spcs_log("sndr", NULL
,
1615 gettext("%s: error locking config"),
1617 rdc_warn(NULL
, gettext("error locking config"));
1622 /* PIT enable or update was fine, so update the ndr_ii entry */
1624 /* get ndr_ii entries until a match is found */
1625 for (i
= 0; ; i
++) {
1628 (void) snprintf(key
, sizeof (key
),
1629 "ndr_ii.set%d.shadow", setnumber
);
1630 if (cfg_get_cstring(cfg
, key
, buf
, CFG_MAX_BUF
) < 0)
1632 if (strcmp(buf
, shadows
[j
]) != 0)
1635 /* Found the matching entry */
1637 (void) snprintf(key
, sizeof (key
), "ndr_ii.set%d.state",
1639 if (cfg_put_cstring(cfg
, key
, NOUPDATE
,
1640 strlen(NOUPDATE
)) < 0) {
1641 spcs_log("sndr", NULL
,
1642 gettext("%s: unable to update \"%s\" "
1643 "in configuration storage: %s"),
1644 program
, buf
, cfg_error(&sev
));
1646 gettext("unable to update \"%s\" "
1647 "in configuration storage: %s"),
1648 buf
, cfg_error(&sev
));
1656 if (cfg_commit(cfg
) < 0)
1657 rdc_warn(NULL
, gettext("commit config error"));
1659 spcs_log("sndr", NULL
,
1660 gettext("%s: group sync: Point-in-Time Copy snapshots completed "
1661 "for %s"), program
, group
);
1673 for (i
= 0; i
< sndr_sets
; i
++) {
1681 for (i
= 0; i
< update_needed
; i
++) {
1689 for (i
= 0; i
< update_needed
; i
++) {