1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/wait.h> 28 #include <stdio.h> 29 #include <errno.h> 30 #include <limits.h> 31 #include <fcntl.h> 32 #include <strings.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <pthread.h> 36 #include <thread.h> 37 38 #include <locale.h> 39 #include <langinfo.h> 40 #include <libintl.h> 41 #include <stdarg.h> 42 43 #include <sys/nsctl/rdc_io.h> 44 #include <sys/nsctl/rdc_ioctl.h> 45 #include <sys/nsctl/rdc_prot.h> 46 47 #include <sys/nsctl/cfg.h> 48 49 #include <sys/unistat/spcs_s.h> 50 #include <sys/unistat/spcs_s_u.h> 51 #include <sys/unistat/spcs_errors.h> 52 53 #include <sys/nsctl/librdc.h> 54 55 #include "rdcadm.h" 56 57 58 #define RDCADM "/usr/sbin/sndradm" 59 #define IIADM "/usr/sbin/iiadm" 60 61 #define UPDATE "update" 62 #define NOUPDATE "noupdate" 63 64 #define RESYNC_SLEEP (3 * 60) /* Three minutes */ 65 #define MAIN_SLEEP (5 * 60) /* Five minutes */ 66 #define CFG_WAIT_SLEEP (5) /* 5 sec */ 67 68 #define MAXHOSTS 1024 69 mutex_t cfglock = DEFAULTMUTEX; 70 #define LOCKCFG() (void) mutex_lock(&cfglock); 71 #define UNLOCKCFG() (void) mutex_unlock(&cfglock); 72 73 typedef struct host_list_s { 74 char *hosts[MAXHOSTS]; 75 int numhosts; 76 int configured[MAXHOSTS]; 77 mutex_t hosts_mutex; 78 } host_list_t; 79 80 host_list_t *host_list; 81 82 extern char *basename(char *); 83 int rdc_maxsets; 84 char *program; 85 86 static int clustered = 0; 87 88 int isnewhost(char *host); 89 void *wait_sync_event(); 90 void *wait_link_down(void *host); 91 void rdc_sync(char *tohost); 92 void remove_from_hostlist(char *host); 93 void sync_start(char *master); 94 void sync_complete(char *master); 95 void cleanup_hostlist(); 96 void group_start(char *group); 97 void group_complete(char *group); 98 99 100 void 101 init_host_list(void) 102 { 103 host_list = calloc(1, sizeof (host_list_t)); 104 if (host_list == NULL) { 105 spcs_log("sndr", NULL, 106 gettext("host list not initialized, cannot run")); 107 rdc_err(NULL, gettext("host list not initialized, cannot run")); 108 } 109 (void) mutex_init(&host_list->hosts_mutex, USYNC_THREAD, NULL); 110 } 111 112 /* ARGSUSED */ 113 #ifdef lint 114 void 115 sndrsyncd_lintmain(argc, argv) 116 #else 117 int 118 main(argc, argv) 119 #endif 120 int argc; 121 char **argv; 122 { 123 rdc_status_t *rdc_info; 124 int size; 125 int i; 126 pid_t pid; 127 spcs_s_info_t ustatus; 128 int rc, trc; 129 int first = 0; 130 char *required; 131 132 (void) setlocale(LC_ALL, ""); 133 (void) textdomain("rdc"); 134 135 ustatus = spcs_s_ucreate(); 136 137 program = basename(argv[0]); 138 139 init_host_list(); 140 141 rc = rdc_check_release(&required); 142 if (rc < 0) { 143 rdc_err(NULL, 144 gettext("unable to determine the current " 145 "Solaris release: %s\n"), strerror(errno)); 146 /* NOTREACHED */ 147 } else if (rc == FALSE) { 148 rdc_err(NULL, 149 gettext("incorrect Solaris release (requires %s)\n"), 150 required); 151 /* NOTREACHED */ 152 } 153 154 clustered = cfg_iscluster(); 155 if (clustered < 0) { 156 rdc_err(NULL, gettext("unable to ascertain environment")); 157 } 158 159 rdc_maxsets = rdc_get_maxsets(); 160 if (rdc_maxsets == -1) { 161 spcs_log("sndr", NULL, 162 gettext("%s: unable to get maxsets value from kernel"), 163 program); 164 rdc_err(NULL, 165 gettext("unable to get maxsets value from kernel")); 166 } 167 size = sizeof (rdc_status_t) + (sizeof (rdc_set_t) * (rdc_maxsets - 1)); 168 rdc_info = malloc(size); 169 if (rdc_info == NULL) { 170 spcs_log("sndr", NULL, 171 gettext("%s: unable to allocate %ld bytes"), 172 program, size); 173 rdc_err(NULL, 174 gettext("unable to allocate %ld bytes"), size); 175 } 176 bzero(rdc_info, size); 177 178 rdc_info->nset = rdc_maxsets; 179 180 /* 181 * Fork off a child that becomes the daemon. 182 */ 183 if ((pid = fork()) > 0) 184 exit(0); 185 else if (pid < 0) { 186 spcs_log("sndr", NULL, 187 gettext("%s: cannot fork: %s"), 188 program, strerror(errno)); 189 rdc_err(NULL, gettext("cannot fork: %s\n"), 190 strerror(errno)); 191 } 192 193 /* 194 * In child - become daemon. 195 */ 196 197 for (i = 0; i < 3; i++) 198 (void) close(i); 199 200 (void) open("/dev/console", O_WRONLY|O_APPEND); 201 (void) dup(0); 202 (void) dup(0); 203 (void) close(0); 204 205 (void) setpgrp(); 206 207 (void) setlocale(LC_ALL, ""); 208 (void) textdomain("rdc"); 209 210 /* launch a thread to wait for sync start and sync stop events */ 211 212 if ((trc = thr_create(NULL, 0, wait_sync_event, NULL, 213 THR_BOUND|THR_DETACHED, NULL)) != 0) { 214 spcs_log("sndr", NULL, 215 gettext("%s: unable to create thread wait_sync_event"), 216 program); 217 rdc_warn(NULL, 218 gettext("%s unable to create thread wait_sync_event"), 219 program); 220 } else { 221 #ifdef DEBUG 222 spcs_log("sndr", NULL, 223 gettext("%s: thread wait_sync_event started"), program); 224 #endif 225 ; 226 } 227 228 for (;;) { 229 if (!first) { 230 first++; 231 (void) sleep(15); 232 } else 233 (void) sleep(MAIN_SLEEP); 234 235 bzero(rdc_info, size); 236 rdc_info->nset = rdc_maxsets; 237 if (RDC_IOCTL(RDC_STATUS, rdc_info, 0, 0, 0, 0, ustatus) 238 != SPCS_S_OK) { 239 spcs_log("sndr", &ustatus, 240 gettext("%s: status ioctl"), 241 program); 242 rdc_warn(&ustatus, gettext("status ioctl")); 243 continue; 244 } 245 246 cleanup_hostlist(rdc_info); /* remove non-existent hosts */ 247 248 /* 249 * Check all enabled sets to see if a new remote host has 250 * appeared. 251 */ 252 for (i = 0; i < rdc_maxsets; i++) { 253 if (!(rdc_info->rdc_set[i].flags & RDC_ENABLED)) 254 continue; 255 /* spawn a new thread for each new host found */ 256 if (isnewhost(rdc_info->rdc_set[i].secondary.intf)) { 257 /* 258 * right now, we could be here before 259 * the database did the write for this set 260 * I could check the lock on the database 261 * but I am just going to give up some time here 262 * instead. Why do the allocations etc, etc 263 * if the set is enabled in the kernel and not 264 * in the config, we know that this set has the 265 * lock. Why bother adding more contention to 266 * the lock. 267 * this is a daemon, afterall. its got time 268 */ 269 (void) sleep(CFG_WAIT_SLEEP); 270 271 spcs_log("sndr", NULL, 272 gettext("%s: new host found (%s) starting " 273 "its autosync thread"), program, 274 rdc_info->rdc_set[i].secondary.intf); 275 276 trc = thr_create(NULL, 0, wait_link_down, 277 (void *) rdc_info->rdc_set[i].\ 278 secondary.intf, THR_BOUND|THR_DETACHED, NULL); 279 280 if (trc != 0) { 281 spcs_log("sndr", NULL, 282 gettext( 283 "%s create new autosync " 284 "thread failed"), program); 285 rdc_warn(NULL, gettext( 286 "%s create new autosync " 287 "thread failed"), program); 288 } 289 } 290 } 291 } 292 /* NOTREACHED */ 293 } 294 295 296 /* 297 * The kernel wakes up this function every time it detects the link to the 298 * specified host has dropped. 299 */ 300 void * 301 wait_link_down(void *thehost) 302 { 303 char *host = (char *)thehost; 304 char tmphost[MAX_RDC_HOST_SIZE] = { '\0' }; 305 spcs_s_info_t ustatus; 306 307 if (host) 308 strncpy(tmphost, host, MAX_RDC_HOST_SIZE); 309 310 ustatus = spcs_s_ucreate(); 311 312 /* Never give up */ 313 for (;;) { 314 #ifdef DEBUG 315 spcs_log("sndr", NULL, 316 gettext("%s: awaiting link down ioctl for %s"), 317 program, host[0] == '\0' ? tmphost : host); 318 #endif 319 if (RDC_IOCTL(RDC_LINK_DOWN, host, 0, 0, 0, 0, ustatus) 320 != SPCS_S_OK) { 321 spcs_log("sndr", &ustatus, 322 gettext("%s: link down ioctl"), 323 program); 324 rdc_warn(&ustatus, gettext("link down ioctl")); 325 continue; 326 } 327 #ifdef DEBUG 328 329 spcs_log("sndr", NULL, 330 gettext("%s: received link down ioctl for %s"), 331 program, host[0] == '\0' ? tmphost : host); 332 #endif 333 rdc_sync(host[0] == '\0' ? tmphost : host); 334 } 335 /* LINTED */ 336 } 337 338 339 /* 340 * Called when the link to the specified host has dropped. 341 * For all Remote Mirror sets using the link that have autosync on, 342 * issue rdcadm -u commands until they complete successfully. 343 */ 344 void 345 rdc_sync(char *tohost) 346 { 347 rdc_set_t *rdc_set = NULL; 348 int *sync_done = NULL; 349 int sets = 0; 350 int syncs_done = 0; 351 char cmd[256]; 352 rdc_config_t parms = { 0 }; 353 spcs_s_info_t ustatus; 354 int i; 355 int setnumber; 356 int numfound = 0; 357 char buf[CFG_MAX_BUF]; 358 char key[CFG_MAX_KEY]; 359 CFGFILE *cfg = NULL; 360 int size; 361 int first = 0; 362 int death = 0; 363 int cfglocked = 0; 364 365 ustatus = spcs_s_ucreate(); 366 367 size = sizeof (rdc_set_t) * rdc_maxsets; 368 rdc_set = malloc(size); 369 if (rdc_set == NULL) { 370 spcs_log("sndr", NULL, 371 gettext("%s: unable to allocate %ld bytes"), 372 program, size); 373 rdc_warn(NULL, 374 gettext("unable to allocate %ld bytes"), size); 375 goto done; 376 } 377 bzero(rdc_set, size); 378 size = sizeof (int) * rdc_maxsets; 379 sync_done = malloc(size); 380 if (sync_done == NULL) { 381 spcs_log("sndr", NULL, 382 gettext("%s: unable to allocate %ld bytes"), 383 program, size); 384 rdc_warn(NULL, 385 gettext("unable to allocate %ld bytes"), size); 386 goto done; 387 } 388 bzero(sync_done, size); 389 390 /* 391 * Get all sndr entries with shost matching tohost, and save the 392 * details in an array. 393 */ 394 for (i = 0; i < rdc_maxsets; i++) { 395 setnumber = i + 1; 396 bzero(buf, sizeof (buf)); 397 bzero(key, sizeof (key)); 398 399 (void) snprintf(key, sizeof (key), "sndr.set%d.shost", 400 setnumber); 401 402 if (!cfglocked) { 403 LOCKCFG(); 404 if ((cfg = cfg_open(NULL)) == NULL) { 405 spcs_log("sndr", NULL, 406 gettext("%s: error opening config"), 407 program); 408 409 rdc_warn(NULL, 410 gettext("error opening config")); 411 UNLOCKCFG(); 412 goto done; 413 } 414 415 if (!cfg_lock(cfg, CFG_RDLOCK)) { 416 spcs_log("sndr", NULL, 417 gettext("%s: error locking config"), 418 program); 419 rdc_warn(NULL, gettext("error locking config")); 420 goto done; 421 } 422 } 423 424 cfglocked = 1; 425 426 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 427 if (numfound == 0) /* no matching hosts */ 428 death = 1; /* thread will exit */ 429 break; 430 } 431 if (strcmp(buf, tohost) != 0) 432 continue; 433 434 numfound++; 435 strncpy(rdc_set[sets].secondary.intf, buf, MAX_RDC_HOST_SIZE); 436 437 /* Got a matching entry */ 438 439 (void) snprintf(key, sizeof (key), "sndr.set%d.phost", 440 setnumber); 441 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 442 break; 443 strncpy(rdc_set[sets].primary.intf, buf, MAX_RDC_HOST_SIZE); 444 445 (void) snprintf(key, sizeof (key), "sndr.set%d.primary", 446 setnumber); 447 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 448 break; 449 strncpy(rdc_set[sets].primary.file, buf, NSC_MAXPATH); 450 451 (void) snprintf(key, sizeof (key), "sndr.set%d.secondary", 452 setnumber); 453 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 454 break; 455 strncpy(rdc_set[sets].secondary.file, buf, NSC_MAXPATH); 456 457 parms.command = RDC_CMD_STATUS; 458 bcopy((void *)(&rdc_set[sets]), (void *)(&parms.rdc_set[0]), 459 sizeof (rdc_set_t)); 460 461 /* 462 * release cfg before diving into the kernel 463 * this prevents a possible deadlock when doing 464 * a reverse sync whick will wake up the sync_event 465 * thread which will try and iiadm -c and hang 466 * because we still have the cfg_lock. the timed 467 * wait cv in the kernel will fail the sync and things 468 * will undeadlock. 469 */ 470 471 cfg_close(cfg); 472 cfg = NULL; 473 cfglocked = 0; 474 UNLOCKCFG(); 475 476 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus) < 0) { 477 continue; 478 } 479 if ((parms.rdc_set[0].autosync == 0) || 480 (!(parms.rdc_set[0].flags & RDC_LOGGING))) { 481 continue; 482 } 483 484 /* Found a suitable set with autosync on, in logging mode */ 485 sets++; 486 } 487 488 if (cfg) { 489 cfg_close(cfg); 490 cfg = NULL; 491 UNLOCKCFG(); 492 } 493 494 if (sets == 0) { 495 #ifdef DEBUG 496 spcs_log("sndr", NULL, 497 gettext("%s: no sets requiring autosync found for %s"), 498 program, tohost); 499 #endif 500 if (death) { 501 spcs_log("sndr", NULL, 502 gettext("%s: autosync thread stopping for %s " 503 "(host deconfigured)"), program, tohost); 504 } 505 goto done; 506 } 507 508 /* Keep issuing rdcadm -u commands until they have all completed */ 509 for (;;) { 510 if (!first) 511 first++; 512 else 513 (void) sleep(RESYNC_SLEEP); 514 515 /* Issue rdcadm -u commands for all remaining sets */ 516 for (i = 0; i < sets; i++) { 517 if (sync_done[i]) 518 continue; 519 520 /* 521 * Need to check if autosync was turned off for a set 522 * while we were sleeping. We could have the case where 523 * an update sync failed and autosync was disabled 524 * while we were sleeping and didn't detect the disable. 525 * See BugID 4814213. 526 */ 527 parms.command = RDC_CMD_STATUS; 528 bcopy((void *)(&rdc_set[i]), 529 (void *)(&parms.rdc_set[0]), sizeof (rdc_set_t)); 530 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, 531 ustatus) < 0) { 532 spcs_log("sndr", &ustatus, gettext("%s: " 533 "status not available for %s:%s, stopping " 534 "this autosync attempt"), program, tohost, 535 rdc_set[i].secondary.file); 536 sync_done[i] = 1; 537 syncs_done++; 538 continue; 539 } 540 if (!(parms.rdc_set[0].autosync)) { 541 #ifdef DEBUG 542 spcs_log("sndr", NULL, gettext("%s: autosync disabled during sleep, " 543 "stopping attempt for set %s:%s"), program, tohost, 544 rdc_set[i].secondary.file); 545 #endif 546 sync_done[i] = 1; 547 syncs_done++; 548 continue; 549 } 550 551 (void) sprintf(cmd, "%s -un %s:%s", RDCADM, tohost, 552 rdc_set[i].secondary.file); 553 spcs_log("sndr", NULL, 554 gettext("%s: issuing update sync for %s:%s"), 555 program, tohost, rdc_set[i].secondary.file); 556 (void) system(cmd); 557 } 558 559 /* Issue rdcadm -w commands to wait for updates to finish */ 560 for (i = 0; i < sets; i++) { 561 if (sync_done[i]) 562 continue; 563 564 (void) sprintf(cmd, "%s -wn %s:%s", RDCADM, tohost, 565 rdc_set[i].secondary.file); 566 spcs_log("sndr", NULL, 567 gettext("%s: issuing wait for %s:%s"), 568 program, tohost, rdc_set[i].secondary.file); 569 570 (void) system(cmd); 571 572 parms.command = RDC_CMD_STATUS; 573 bcopy((void *)(&rdc_set[i]), 574 (void *)(&parms.rdc_set[0]), sizeof (rdc_set_t)); 575 576 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, 577 ustatus) < 0) { 578 spcs_log("sndr", &ustatus, 579 gettext("%s: status not available for " 580 "%s:%s, stopping this autosync attempt"), 581 program, tohost, rdc_set[i].secondary.file); 582 sync_done[i] = 1; 583 syncs_done++; 584 continue; 585 } 586 /* Check if completed OK, failed or autosync off */ 587 if (!(parms.rdc_set[0].autosync) || 588 !(parms.rdc_set[0].flags & RDC_LOGGING) && 589 !(parms.rdc_set[0].flags & RDC_SYNCING)) { 590 sync_done[i] = 1; 591 syncs_done++; 592 } 593 } 594 595 if (syncs_done == sets) 596 break; /* All completed OK */ 597 } 598 599 done: 600 if (cfg) { 601 cfg_close(cfg); 602 UNLOCKCFG(); 603 } 604 spcs_s_ufree(&ustatus); 605 if (sync_done) 606 free(sync_done); 607 if (rdc_set) 608 free(rdc_set); 609 if (death) { /* bye bye */ 610 /* 611 * if perhaps we lost some race, lets remove this entry from 612 * the list. Then, if something did go wrong, and we did kill 613 * a valid thread, it will be detected on the next go around 614 * of the thread who is looking for new hosts to spawn threads 615 */ 616 617 remove_from_hostlist(tohost); 618 thr_exit(0); 619 } 620 621 (void) sleep(RESYNC_SLEEP); 622 } 623 624 /* 625 * Wait for notification by the kernel of a sync start or a sync completed OK 626 */ 627 void * 628 wait_sync_event() 629 { 630 spcs_s_info_t ustatus; 631 char master[NSC_MAXPATH]; 632 char group[NSC_MAXPATH]; 633 int state; 634 635 ustatus = spcs_s_ucreate(); 636 637 master[0] = '\0'; 638 group[0] = '\0'; 639 640 /* Never give up */ 641 for (;;) { 642 /* Kernel tells us which volume and group the event is for */ 643 state = RDC_IOCTL(RDC_SYNC_EVENT, master, group, 0, 0, 0, 644 ustatus); 645 if (state < SPCS_S_OK) { 646 if (errno != EAGAIN) { 647 spcs_log("sndr", &ustatus, 648 gettext("%s: update ioctl"), 649 program); 650 rdc_warn(&ustatus, gettext("update ioctl")); 651 continue; 652 } 653 master[0] = '\0'; 654 continue; 655 } 656 657 /* 658 * If target is mounted at the start of a sync or reverse sync, 659 * return a negative ack. 660 */ 661 if ((state == RDC_SYNC_START || state == RDC_RSYNC_START) && 662 mounted(master)) { 663 spcs_log("sndr", NULL, 664 gettext("%s: %s has a file system mounted"), 665 program, master); 666 rdc_warn(NULL, 667 gettext("%s has a file system mounted"), 668 master); 669 master[0] = '\0'; /* negative ack */ 670 continue; 671 } 672 673 switch (state) { 674 case RDC_SYNC_START: 675 if (group[0]) 676 group_start(group); 677 else 678 sync_start(master); 679 break; 680 681 case RDC_SYNC_DONE: 682 if (group[0]) 683 group_complete(group); 684 else 685 sync_complete(master); 686 break; 687 688 default: 689 break; 690 } 691 } 692 /* LINTED */ 693 } 694 695 696 /* 697 * A sync has completed OK to a volume not belonging to a group. 698 * Set the state of the ndr_ii config entry to "update". 699 */ 700 void 701 sync_complete(char *master) 702 { 703 CFGFILE *cfg = NULL; 704 char buf[CFG_MAX_BUF]; 705 char key[CFG_MAX_KEY]; 706 int i; 707 int setnumber; 708 int sev; 709 710 LOCKCFG(); 711 if ((cfg = cfg_open(NULL)) == NULL) { 712 spcs_log("sndr", NULL, 713 gettext("%s: error opening config"), 714 program); 715 rdc_warn(NULL, gettext("error opening config")); 716 UNLOCKCFG(); 717 return; 718 } 719 if (!cfg_lock(cfg, CFG_WRLOCK)) { 720 spcs_log("sndr", NULL, 721 gettext("%s: error locking config"), 722 program); 723 rdc_warn(NULL, gettext("error locking config")); 724 cfg_close(cfg); 725 UNLOCKCFG(); 726 return; 727 } 728 729 /* get ndr_ii entries until a match is found */ 730 for (i = 0; ; i++) { 731 setnumber = i + 1; 732 733 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary", 734 setnumber); 735 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 736 break; 737 if (strcmp(buf, master) != 0) 738 continue; 739 740 /* Found the matching entry */ 741 742 /* 743 * Set state to "update" so that starting another sync will 744 * cause a new Point-in-Time Copy snapshot to be taken. 745 */ 746 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state", 747 setnumber); 748 if ((cfg_put_cstring(cfg, key, UPDATE, strlen(UPDATE)) < 0) || 749 (cfg_commit(cfg) < 0)) { 750 spcs_log("sndr", NULL, 751 gettext("%s: unable to update \"%s\" " 752 "in configuration storage: %s"), 753 program, buf, cfg_error(&sev)); 754 rdc_warn(NULL, 755 gettext("unable to update \"%s\" " 756 "in configuration storage: %s"), 757 buf, cfg_error(&sev)); 758 } 759 break; 760 } 761 762 cfg_close(cfg); 763 UNLOCKCFG(); 764 } 765 766 767 /* 768 * Starting a sync to the specified master volume. 769 * Check the ndr_ii config entries to see if a Point-in-Time Copy 770 * snapshot should be taken. 771 */ 772 void 773 sync_start(char *master) 774 { 775 char cmd[256]; 776 char buf[CFG_MAX_BUF]; 777 char key[CFG_MAX_KEY]; 778 CFGFILE *cfg = NULL; 779 int i; 780 int setnumber; 781 int found; 782 int sev; 783 char shadow[NSC_MAXPATH]; 784 char bitmap[NSC_MAXPATH]; 785 char *ctag = NULL; 786 787 LOCKCFG(); 788 if ((cfg = cfg_open(NULL)) == NULL) { 789 spcs_log("sndr", NULL, 790 gettext("%s: error opening config"), 791 program); 792 rdc_warn(NULL, 793 gettext("error opening config")); 794 UNLOCKCFG(); 795 return; 796 } 797 if (!cfg_lock(cfg, CFG_RDLOCK)) { 798 spcs_log("sndr", NULL, 799 gettext("%s: error locking config"), 800 program); 801 rdc_warn(NULL, gettext("error locking config")); 802 cfg_close(cfg); 803 UNLOCKCFG(); 804 return; 805 } 806 807 found = 0; 808 /* get ndr_ii entries until a match is found */ 809 for (i = 0; ; i++) { 810 setnumber = i + 1; 811 812 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary", 813 setnumber); 814 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 815 break; 816 if (strcmp(buf, master) != 0) 817 continue; 818 819 /* Got a matching entry */ 820 821 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.shadow", 822 setnumber); 823 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 824 break; 825 strncpy(shadow, buf, NSC_MAXPATH); 826 827 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.bitmap", 828 setnumber); 829 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 830 break; 831 strncpy(bitmap, buf, NSC_MAXPATH); 832 833 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state", 834 setnumber); 835 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 836 break; 837 838 /* 839 * If an PIT snapshot has already been taken, and syncing did 840 * not complete, the state will be "noupdate", to indicate we 841 * should not take another one at this point. 842 */ 843 if (strcmp(buf, NOUPDATE) != 0) 844 found = 1; 845 846 break; 847 } 848 849 if (!found) { 850 cfg_close(cfg); 851 UNLOCKCFG(); 852 return; 853 } 854 855 found = 0; 856 /* get ii entries until a match is found */ 857 for (i = 0; ; i++) { 858 setnumber = i + 1; 859 860 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", 861 setnumber); 862 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 863 break; 864 if (strcmp(buf, shadow) != 0) 865 continue; 866 867 /* Matching shadow found, so ii already enabled */ 868 found = 1; 869 break; 870 } 871 872 if (found) { 873 /* Already PIT enabled, so just take a snapshot */ 874 875 /* Get cluster tag of matching entry */ 876 (void) snprintf(key, sizeof (key), "ii.set%d.cnode", setnumber); 877 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) >= 0) 878 if ((strlen(buf) == 0) || (buf[0] == '-')) 879 ctag = "-C local"; 880 else 881 ctag = ""; 882 (void) sprintf(cmd, "%s %s -u s %s", IIADM, ctag, shadow); 883 } else { 884 /* 885 * If clustered, need to enable PIT Copy sets in the same 886 * cluster as the Remote Mirror set 887 */ 888 889 if (clustered) { 890 /* Find a RM set with master as the local volume */ 891 892 for (i = 0; i < rdc_maxsets; i++) { 893 setnumber = i + 1; 894 (void) snprintf(key, sizeof (key), 895 "sndr.set%d.phost", setnumber); 896 if (cfg_get_cstring(cfg, key, buf, 897 CFG_MAX_BUF) < 0) 898 break; 899 900 if (self_check(buf)) 901 (void) snprintf(key, sizeof (key), 902 "sndr.set%d.primary", setnumber); 903 else 904 (void) snprintf(key, sizeof (key), 905 "sndr.set%d.secondary", setnumber); 906 if (cfg_get_cstring(cfg, key, buf, 907 CFG_MAX_BUF) < 0) 908 break; 909 910 if (strcmp(buf, master) != 0) 911 continue; 912 913 /* Get cluster tag of matching entry */ 914 915 (void) snprintf(key, sizeof (key), 916 "sndr.set%d.cnode", setnumber); 917 if (cfg_get_cstring(cfg, key, buf, 918 CFG_MAX_BUF) < 0) 919 break; 920 if ((strlen(buf) == 0) || (buf[0] == '-')) 921 ctag = strdup("local"); 922 else 923 ctag = strdup(buf); 924 break; 925 } 926 } 927 928 /* Not already enabled, so enable a dependent */ 929 if (ctag) { 930 (void) sprintf(cmd, "%s -C %s -e dep %s %s %s", IIADM, 931 ctag, master, shadow, bitmap); 932 free(ctag); 933 } else 934 (void) sprintf(cmd, "%s -e dep %s %s %s", IIADM, master, 935 shadow, bitmap); 936 } 937 938 cfg_close(cfg); 939 940 if (system(cmd) != 0) { 941 spcs_log("sndr", NULL, 942 gettext("Point-in-Time Copy snapshot failed for %s %s %s." 943 " Please check validity of ndr_ii entry"), 944 master, shadow, bitmap); 945 cfg_close(cfg); 946 UNLOCKCFG(); 947 return; 948 } 949 950 /* 951 * PIT Copy enable or update was fine, so update the ndr_ii entry 952 * to "noupdate", to prevent invalid point in time copies. 953 */ 954 955 if ((cfg = cfg_open(NULL)) == NULL) { 956 spcs_log("sndr", NULL, 957 gettext("%s: error opening config"), 958 program); 959 rdc_warn(NULL, 960 gettext("error opening config")); 961 UNLOCKCFG(); 962 return; 963 } 964 if (!cfg_lock(cfg, CFG_WRLOCK)) { 965 spcs_log("sndr", NULL, 966 gettext("%s: error locking config"), 967 program); 968 rdc_warn(NULL, gettext("error locking config")); 969 cfg_close(cfg); 970 UNLOCKCFG(); 971 return; 972 } 973 974 /* get ndr_ii entries until a match is found */ 975 for (i = 0; ; i++) { 976 setnumber = i + 1; 977 978 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.shadow", 979 setnumber); 980 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 981 break; 982 if (strcmp(buf, shadow) != 0) 983 continue; 984 985 /* Found the matching entry */ 986 987 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state", 988 setnumber); 989 if ((cfg_put_cstring(cfg, key, NOUPDATE, 990 strlen(NOUPDATE)) < 0) || (cfg_commit(cfg) < 0)) { 991 spcs_log("sndr", NULL, 992 gettext("%s: unable to update \"%s\" " 993 "in configuration storage: %s"), 994 program, buf, cfg_error(&sev)); 995 rdc_warn(NULL, 996 gettext("unable to update \"%s\" " 997 "in configuration storage: %s"), 998 buf, cfg_error(&sev)); 999 } 1000 break; 1001 } 1002 cfg_close(cfg); 1003 UNLOCKCFG(); 1004 } 1005 1006 void 1007 cleanup_hostlist(rdc_status_t *rdc_info) 1008 { 1009 int i, j, k; 1010 char *host, *exhost; 1011 1012 1013 (void) mutex_lock(&host_list->hosts_mutex); 1014 for (i = 0; i < host_list->numhosts; i++) { 1015 int found = 0; 1016 for (j = 0; (j < rdc_maxsets) && !found; j++) { 1017 if (!rdc_info->rdc_set[j].flags & RDC_ENABLED) 1018 continue; 1019 if ((!host_list->configured[i]) || 1020 (host_list->hosts[i] == '\0')) { 1021 (void) mutex_unlock(&host_list->hosts_mutex); 1022 return; 1023 } 1024 1025 host = rdc_info->rdc_set[j].secondary.intf; 1026 if (strcmp(host_list->hosts[i], host) == 0) 1027 found++; 1028 } 1029 if (j == rdc_maxsets) { 1030 /* 1031 * this set is not in the kernel, so remove from list 1032 */ 1033 exhost = host_list->hosts[i]; 1034 if (exhost) { 1035 free(exhost); 1036 exhost = NULL; 1037 } 1038 1039 k = i; 1040 while (k < host_list->numhosts) { 1041 host_list->hosts[k] = k < host_list->numhosts - 1 ? 1042 host_list->hosts[k+1] : NULL; 1043 k++; 1044 } 1045 host_list->numhosts--; 1046 1047 bcopy(&host_list->configured[i+1], 1048 &host_list->configured[i], 1049 (MAXHOSTS - i + 1) * sizeof (int)); 1050 host_list->configured[MAXHOSTS - 1] = 0; 1051 } 1052 } 1053 (void) mutex_unlock(&host_list->hosts_mutex); 1054 } 1055 1056 /* 1057 * explicity remove a host from the host list 1058 * also update the configured array 1059 * called in rdc_sync, just before exiting a thread. 1060 */ 1061 void 1062 remove_from_hostlist(char *host) 1063 { 1064 int i, k; 1065 char *exhost; 1066 1067 /* why bother? */ 1068 if ((!host) || (host[0] == '\0')) 1069 return; 1070 1071 (void) mutex_lock(&host_list->hosts_mutex); 1072 for (i = 0; i < host_list->numhosts; i++) { 1073 if (strcmp(host, host_list->hosts[i]) == 0) { /* found it */ 1074 exhost = host_list->hosts[i]; 1075 if (exhost) { 1076 free(exhost); 1077 exhost = NULL; 1078 } 1079 k = i; 1080 while (k < host_list->numhosts) { 1081 host_list->hosts[k] = k < host_list->numhosts - 1 ? 1082 host_list->hosts[k+1] : NULL; 1083 k++; 1084 } 1085 host_list->numhosts--; 1086 bcopy(&host_list->configured[i+1], 1087 &host_list->configured[i], 1088 (MAXHOSTS - i + 1) * sizeof (int)); 1089 host_list->configured[MAXHOSTS - 1] = 0; 1090 } 1091 1092 } 1093 (void) mutex_unlock(&host_list->hosts_mutex); 1094 } 1095 /* 1096 * Check to see if this host isn't in our list, so needs a new rdcsyncd proc 1097 */ 1098 int 1099 isnewhost(char *host) 1100 { 1101 int i; 1102 int new; 1103 1104 if (self_check(host)) { 1105 return (0); 1106 } 1107 1108 (void) mutex_lock(&host_list->hosts_mutex); 1109 new = 1; 1110 for (i = 0; i < MAXHOSTS; i++) { 1111 if (host_list->configured[i] == 0) { 1112 host_list->configured[i] = 1; 1113 host_list->hosts[i] = strdup(host); 1114 host_list->numhosts++; 1115 break; 1116 } 1117 if (strcmp(host, host_list->hosts[i]) == 0) { 1118 new = 0; 1119 break; 1120 } 1121 } 1122 (void) mutex_unlock(&host_list->hosts_mutex); 1123 if (i == MAXHOSTS) 1124 new = 0; 1125 return (new); 1126 } 1127 1128 1129 /* 1130 * Look for a matching volume name in our remembered list. 1131 */ 1132 int 1133 volume_match(char *buf, char **volume_list, int volumes) 1134 { 1135 int i; 1136 char *vol; 1137 1138 for (i = 0; i < volumes; i++) { 1139 vol = volume_list[i]; 1140 if (strcmp(buf, vol) == 0) { 1141 return (1); 1142 } 1143 } 1144 return (0); 1145 } 1146 1147 1148 /* 1149 * A sync has completed to a group. We can only update the ndr_ii entries 1150 * if all the members of the group have completed their syncs OK. 1151 * It would be bad to allow some members of the group to have PIT Copy snapshots 1152 * taken and others not, as they need to be consistent. 1153 */ 1154 void 1155 group_complete(char *group) 1156 { 1157 char **volumes = NULL; 1158 spcs_s_info_t ustatus; 1159 rdc_config_t parms = { 0 }; 1160 char buf[CFG_MAX_BUF]; 1161 char key[CFG_MAX_KEY]; 1162 CFGFILE *cfg = NULL; 1163 int i; 1164 int setnumber; 1165 int found; 1166 int replicating = 0; 1167 char primary[NSC_MAXPATH]; 1168 char secondary[NSC_MAXPATH]; 1169 char phost[MAX_RDC_HOST_SIZE]; 1170 char shost[MAX_RDC_HOST_SIZE]; 1171 rdc_set_t *rdc_set; 1172 int sev; 1173 char *local_file; 1174 int size; 1175 1176 ustatus = spcs_s_ucreate(); 1177 1178 size = sizeof (char *) * rdc_maxsets; 1179 volumes = malloc(size); 1180 if (volumes == NULL) { 1181 spcs_log("sndr", NULL, 1182 gettext("%s: unable to allocate %ld bytes"), 1183 program, size); 1184 rdc_warn(NULL, 1185 gettext("unable to allocate %ld bytes"), size); 1186 goto done; 1187 } 1188 bzero(volumes, size); 1189 1190 /* 1191 * If all members of this group are replicating 1192 * set ii_ndr state to "update". Otherwise leave them alone. 1193 */ 1194 LOCKCFG(); 1195 if ((cfg = cfg_open(NULL)) == NULL) { 1196 spcs_log("sndr", NULL, 1197 gettext("%s: error opening lconfig"), 1198 program); 1199 rdc_warn(NULL, gettext("error opening config")); 1200 UNLOCKCFG(); 1201 goto done; 1202 } 1203 1204 if (!cfg_lock(cfg, CFG_RDLOCK)) { 1205 spcs_log("sndr", NULL, 1206 gettext("%s: error locking config"), 1207 program); 1208 rdc_warn(NULL, gettext("error locking config")); 1209 goto done; 1210 } 1211 1212 found = 0; 1213 1214 /* get all RM entries, with a matching group, that are replicating */ 1215 for (i = 0; i < rdc_maxsets; i++) { 1216 setnumber = i + 1; 1217 1218 (void) snprintf(key, sizeof (key), 1219 "sndr.set%d.group", setnumber); 1220 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 1221 break; 1222 1223 if (strcmp(buf, group) != 0) 1224 continue; 1225 1226 /* Found a matching entry */ 1227 1228 (void) snprintf(key, sizeof (key), 1229 "sndr.set%d.primary", setnumber); 1230 if (cfg_get_cstring(cfg, key, primary, sizeof (primary)) < 0) 1231 break; 1232 strcpy(parms.rdc_set->primary.file, primary); 1233 1234 (void) snprintf(key, sizeof (key), 1235 "sndr.set%d.phost", setnumber); 1236 if (cfg_get_cstring(cfg, key, phost, sizeof (phost)) < 0) 1237 break; 1238 strcpy(parms.rdc_set->primary.intf, phost); 1239 1240 (void) snprintf(key, sizeof (key), 1241 "sndr.set%d.secondary", setnumber); 1242 if (cfg_get_cstring(cfg, key, secondary, 1243 sizeof (secondary)) < 0) 1244 break; 1245 strcpy(parms.rdc_set->secondary.file, secondary); 1246 1247 (void) snprintf(key, sizeof (key), 1248 "sndr.set%d.shost", setnumber); 1249 if (cfg_get_cstring(cfg, key, shost, sizeof (shost)) < 0) 1250 break; 1251 strcpy(parms.rdc_set->secondary.intf, shost); 1252 1253 parms.command = RDC_CMD_STATUS; 1254 if (RDC_IOCTL(RDC_CONFIG, &parms, NULL, 0, 0, 0, ustatus) < 0) { 1255 continue; 1256 } 1257 1258 /* We found a matching set */ 1259 found++; 1260 1261 if (self_check(phost)) 1262 local_file = primary; 1263 else 1264 local_file = secondary; 1265 1266 rdc_set = &parms.rdc_set[0]; 1267 if (!(rdc_set->flags & RDC_LOGGING) && 1268 !(rdc_set->flags & RDC_SYNCING)) { 1269 volumes[replicating] = strdup(local_file); 1270 if (volumes[replicating] == NULL) { 1271 size = strlen(local_file); 1272 spcs_log("sndr", NULL, 1273 gettext("%s: unable to allocate %ld bytes"), 1274 program, size); 1275 rdc_warn(NULL, 1276 gettext("unable to allocate %ld bytes"), 1277 size); 1278 goto done; 1279 } 1280 /* We remember all replicating sets */ 1281 replicating++; 1282 } else 1283 break; /* Not all replicating, so done */ 1284 } 1285 1286 if (found != replicating) 1287 goto done; 1288 1289 /* All replicating, so update ndr_ii state fields */ 1290 1291 cfg_unlock(cfg); 1292 1293 if (!cfg_lock(cfg, CFG_WRLOCK)) { 1294 spcs_log("sndr", NULL, 1295 gettext("%s: error locking lconfig"), 1296 program); 1297 rdc_warn(NULL, gettext("error locking config")); 1298 goto done; 1299 } 1300 1301 /* 1302 * Search through the ndr_ii entries for entries 1303 * that match the saved secondary volume names. 1304 * Set state to "update". 1305 */ 1306 1307 for (i = 0; ; i++) { 1308 setnumber = i + 1; 1309 1310 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary", 1311 setnumber); 1312 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 1313 break; 1314 1315 if (!volume_match(buf, volumes, found)) { 1316 continue; 1317 } 1318 1319 /* Got a matching entry */ 1320 1321 (void) snprintf(key, sizeof (key), 1322 "ndr_ii.set%d.state", setnumber); 1323 if ((cfg_put_cstring(cfg, key, UPDATE, strlen(UPDATE)) < 0) || 1324 (cfg_commit(cfg) < 0)) { 1325 spcs_log("sndr", NULL, 1326 gettext("%s: unable to update \"%s\" " 1327 "in configuration storage: %s"), 1328 program, buf, cfg_error(&sev)); 1329 rdc_warn(NULL, 1330 gettext("unable to update \"%s\" " 1331 "in configuration storage: %s"), 1332 buf, cfg_error(&sev)); 1333 } 1334 } 1335 1336 1337 done: 1338 if (cfg) { 1339 cfg_close(cfg); 1340 UNLOCKCFG(); 1341 } 1342 spcs_s_ufree(&ustatus); 1343 if (volumes) { 1344 for (i = 0; i < replicating; i++) 1345 free(volumes[i]); 1346 free(volumes); 1347 } 1348 } 1349 1350 1351 /* 1352 * Sync started to a member of a group. 1353 * If all members of the group are in ndr_ii state "update" then take an PIT 1354 * snapshot on all of them. This will provide a consistent point-in-time 1355 * copy until whatever syncs take place are all completed. 1356 */ 1357 void 1358 group_start(char *group) 1359 { 1360 char **masters = NULL; 1361 char **shadows = NULL; 1362 char **bitmaps = NULL; 1363 char cmd[256]; 1364 char buf[CFG_MAX_BUF]; 1365 char key[CFG_MAX_KEY]; 1366 CFGFILE *cfg = NULL; 1367 int i; 1368 int j; 1369 int setnumber; 1370 int found; 1371 int sndr_sets = 0; 1372 int update_needed = 0; 1373 int sev; 1374 char *ctag = NULL; 1375 int commit = 0; 1376 int size; 1377 1378 size = sizeof (char *) * rdc_maxsets; 1379 masters = malloc(size); 1380 if (masters == NULL) { 1381 spcs_log("sndr", NULL, 1382 gettext("%s: unable to allocate %ld bytes"), 1383 program, size); 1384 rdc_warn(NULL, 1385 gettext("unable to allocate %ld bytes"), size); 1386 goto done; 1387 } 1388 bzero(masters, size); 1389 shadows = malloc(size); 1390 if (shadows == NULL) { 1391 spcs_log("sndr", NULL, 1392 gettext("%s: unable to allocate %ld bytes"), 1393 program, size); 1394 rdc_warn(NULL, 1395 gettext("unable to allocate %ld bytes"), size); 1396 goto done; 1397 } 1398 bzero(shadows, size); 1399 bitmaps = malloc(size); 1400 if (bitmaps == NULL) { 1401 spcs_log("sndr", NULL, 1402 gettext("%s: unable to allocate %ld bytes"), 1403 program, size); 1404 rdc_warn(NULL, 1405 gettext("unable to allocate %ld bytes"), size); 1406 goto done; 1407 } 1408 bzero(bitmaps, size); 1409 1410 LOCKCFG(); 1411 if ((cfg = cfg_open(NULL)) == NULL) { 1412 spcs_log("sndr", NULL, 1413 gettext("%s: error opening config"), 1414 program); 1415 rdc_warn(NULL, 1416 gettext("error opening config")); 1417 UNLOCKCFG(); 1418 goto done; 1419 } 1420 1421 if (!cfg_lock(cfg, CFG_WRLOCK)) { 1422 spcs_log("sndr", NULL, 1423 gettext("%s: error locking config"), 1424 program); 1425 rdc_warn(NULL, gettext("error locking config")); 1426 goto done; 1427 } 1428 1429 /* Now get all Remote Mirror entries with a matching group */ 1430 for (i = 0; i < rdc_maxsets; i++) { 1431 setnumber = i + 1; 1432 1433 (void) snprintf(key, sizeof (key), 1434 "sndr.set%d.group", setnumber); 1435 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 1436 break; 1437 1438 if (strcmp(buf, group) != 0) 1439 continue; 1440 1441 /* Found a matching entry */ 1442 1443 (void) snprintf(key, sizeof (key), 1444 "sndr.set%d.phost", setnumber); 1445 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) 1446 break; 1447 1448 if (self_check(buf)) { 1449 (void) snprintf(key, sizeof (key), "sndr.set%d.primary", 1450 setnumber); 1451 } else { 1452 (void) snprintf(key, sizeof (key), 1453 "sndr.set%d.secondary", setnumber); 1454 } 1455 if (cfg_get_cstring(cfg, key, buf, sizeof (buf)) < 0) 1456 break; 1457 1458 masters[sndr_sets] = strdup(buf); 1459 if (masters[sndr_sets] == NULL) { 1460 size = strlen(buf); 1461 spcs_log("sndr", NULL, 1462 gettext("%s: unable to allocate %ld bytes"), 1463 program, size); 1464 rdc_warn(NULL, 1465 gettext("unable to allocate %ld bytes"), size); 1466 goto done; 1467 } 1468 sndr_sets++; 1469 1470 if (ctag == NULL && clustered) { 1471 /* Get cluster tag of matching entry */ 1472 1473 (void) snprintf(key, sizeof (key), "sndr.set%d.cnode", 1474 setnumber); 1475 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) >= 0) 1476 ctag = strdup(buf); 1477 } 1478 } 1479 1480 /* 1481 * Search through the ndr_ii entries for entries 1482 * that match the saved local volume names and are in "update" state. 1483 */ 1484 1485 update_needed = 0; 1486 1487 for (i = 0; ; i++) { 1488 setnumber = i + 1; 1489 1490 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.secondary", 1491 setnumber); 1492 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 1493 break; 1494 1495 if (!volume_match(buf, masters, sndr_sets)) 1496 continue; 1497 1498 /* Got a matching entry */ 1499 1500 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.shadow", 1501 setnumber); 1502 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 1503 break; 1504 shadows[update_needed] = strdup(buf); 1505 if (shadows[update_needed] == NULL) { 1506 size = strlen(buf); 1507 spcs_log("sndr", NULL, 1508 gettext("%s: unable to allocate %ld bytes"), 1509 program, size); 1510 rdc_warn(NULL, 1511 gettext("unable to allocate %ld bytes"), size); 1512 goto done; 1513 } 1514 1515 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.bitmap", 1516 setnumber); 1517 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 1518 break; 1519 } 1520 bitmaps[update_needed] = strdup(buf); 1521 if (bitmaps[update_needed] == NULL) { 1522 size = strlen(buf); 1523 spcs_log("sndr", NULL, 1524 gettext("%s: unable to allocate %ld bytes"), 1525 program, size); 1526 rdc_warn(NULL, 1527 gettext("unable to allocate %ld bytes"), size); 1528 goto done; 1529 } 1530 1531 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state", 1532 setnumber); 1533 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) { 1534 break; 1535 } 1536 if (strcmp(buf, UPDATE) != 0) { 1537 break; 1538 } 1539 1540 update_needed++; 1541 } 1542 1543 if (update_needed != sndr_sets) { 1544 #ifdef DEBUG 1545 spcs_log("sndr", NULL, 1546 gettext("%s: group sync: no Point-in-Time Copy snapshot " 1547 "for %s"), program, group); 1548 #endif 1549 goto done; 1550 } 1551 1552 /* All RM sets in the group have an ndr_ii entry in "update" state */ 1553 1554 /* Issue PIT Copy snapshot commands for all sets in the group */ 1555 for (j = 0; j < sndr_sets; j++) { 1556 found = 0; 1557 1558 /* get ii entries until a match is found */ 1559 for (i = 0; ; i++) { 1560 setnumber = i + 1; 1561 1562 (void) snprintf(key, sizeof (key), "ii.set%d.shadow", 1563 setnumber); 1564 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 1565 break; 1566 if (strcmp(buf, shadows[j]) != 0) 1567 continue; 1568 1569 /* Matching shadow found, so ii already enabled */ 1570 found = 1; 1571 break; 1572 } 1573 1574 if (commit) 1575 if (cfg_commit(cfg) < 0) 1576 rdc_warn(NULL, gettext("commit config error")); 1577 cfg_close(cfg); 1578 1579 if (found) { 1580 (void) sprintf(cmd, "%s -u s %s", IIADM, shadows[j]); 1581 } else { 1582 if (ctag) { 1583 (void) sprintf(cmd, "%s -C %s -e dep %s %s %s", 1584 IIADM, ctag, masters[j], shadows[j], 1585 bitmaps[j]); 1586 free(ctag); 1587 ctag = NULL; 1588 } else 1589 (void) sprintf(cmd, "%s -e dep %s %s %s", IIADM, 1590 masters[j], shadows[j], bitmaps[j]); 1591 } 1592 1593 if (system(cmd) != 0) { 1594 spcs_log("sndr", NULL, 1595 gettext("%s: group sync: Point-in-Time Copy" 1596 " snapshot failed for %s"), 1597 program, masters[j]); 1598 1599 goto done; 1600 } 1601 1602 if ((cfg = cfg_open(NULL)) == NULL) { 1603 spcs_log("sndr", NULL, 1604 gettext("%s: error opening config"), 1605 program); 1606 rdc_warn(NULL, 1607 gettext("error opening config")); 1608 goto done; 1609 } 1610 if (!cfg_lock(cfg, CFG_WRLOCK)) { 1611 spcs_log("sndr", NULL, 1612 gettext("%s: error locking config"), 1613 program); 1614 rdc_warn(NULL, gettext("error locking config")); 1615 goto done; 1616 } 1617 commit = 0; 1618 1619 /* PIT enable or update was fine, so update the ndr_ii entry */ 1620 1621 /* get ndr_ii entries until a match is found */ 1622 for (i = 0; ; i++) { 1623 setnumber = i + 1; 1624 1625 (void) snprintf(key, sizeof (key), 1626 "ndr_ii.set%d.shadow", setnumber); 1627 if (cfg_get_cstring(cfg, key, buf, CFG_MAX_BUF) < 0) 1628 break; 1629 if (strcmp(buf, shadows[j]) != 0) 1630 continue; 1631 1632 /* Found the matching entry */ 1633 1634 (void) snprintf(key, sizeof (key), "ndr_ii.set%d.state", 1635 setnumber); 1636 if (cfg_put_cstring(cfg, key, NOUPDATE, 1637 strlen(NOUPDATE)) < 0) { 1638 spcs_log("sndr", NULL, 1639 gettext("%s: unable to update \"%s\" " 1640 "in configuration storage: %s"), 1641 program, buf, cfg_error(&sev)); 1642 rdc_warn(NULL, 1643 gettext("unable to update \"%s\" " 1644 "in configuration storage: %s"), 1645 buf, cfg_error(&sev)); 1646 } else 1647 commit = 1; 1648 break; 1649 } 1650 } 1651 1652 if (commit) 1653 if (cfg_commit(cfg) < 0) 1654 rdc_warn(NULL, gettext("commit config error")); 1655 1656 spcs_log("sndr", NULL, 1657 gettext("%s: group sync: Point-in-Time Copy snapshots completed " 1658 "for %s"), program, group); 1659 1660 done: 1661 if (ctag) 1662 free(ctag); 1663 1664 if (cfg) { 1665 cfg_close(cfg); 1666 UNLOCKCFG(); 1667 } 1668 1669 if (masters) { 1670 for (i = 0; i < sndr_sets; i++) { 1671 if (masters[i]) 1672 free(masters[i]); 1673 } 1674 free(masters); 1675 } 1676 1677 if (shadows) { 1678 for (i = 0; i < update_needed; i++) { 1679 if (shadows[i]) 1680 free(shadows[i]); 1681 } 1682 free(shadows); 1683 } 1684 1685 if (bitmaps) { 1686 for (i = 0; i < update_needed; i++) { 1687 if (bitmaps[i]) 1688 free(bitmaps[i]); 1689 } 1690 free(bitmaps); 1691 } 1692 } 1693