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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <sys/ksynch.h> 28 #include <sys/cmn_err.h> 29 #include <sys/kmem.h> 30 #include <sys/conf.h> 31 #include <sys/errno.h> 32 33 #ifdef _SunOS_5_6 34 /* 35 * on 2.6 both dki_lock.h and rpc/types.h define bool_t so we 36 * define enum_t here as it is all we need from rpc/types.h 37 * anyway and make it look like we included it. Yuck. 38 */ 39 #define _RPC_TYPES_H 40 typedef int enum_t; 41 #else 42 #ifndef DS_DDICT 43 #include <rpc/types.h> 44 #endif 45 #endif /* _SunOS_5_6 */ 46 47 #include <sys/ddi.h> 48 49 #include <sys/nsc_thread.h> 50 #include <sys/nsctl/nsctl.h> 51 52 #include <sys/sdt.h> /* dtrace is S10 or later */ 53 54 #include "rdc_io.h" 55 #include "rdc_bitmap.h" 56 #include "rdc_update.h" 57 #include "rdc_ioctl.h" 58 #include "rdcsrv.h" 59 #include "rdc_diskq.h" 60 61 #include <sys/unistat/spcs_s.h> 62 #include <sys/unistat/spcs_s_k.h> 63 #include <sys/unistat/spcs_errors.h> 64 65 volatile int net_exit; 66 nsc_size_t MAX_RDC_FBAS; 67 68 #ifdef DEBUG 69 int RDC_MAX_SYNC_THREADS = 8; 70 int rdc_maxthreads_last = 8; 71 #endif 72 73 kmutex_t rdc_ping_lock; /* Ping lock */ 74 static kmutex_t net_blk_lock; 75 76 /* 77 * rdc_conf_lock is used as a global device configuration lock. 78 * It is also used by enable/resume and disable/suspend code to ensure that 79 * the transition of an rdc set between configured and unconfigured is 80 * atomic. 81 * 82 * krdc->group->lock is used to protect state changes of a configured rdc 83 * set (e.g. changes to urdc->flags), such as enabled to disabled and vice 84 * versa. 85 * 86 * rdc_many_lock is also used to protect changes in group membership. A group 87 * linked list cannot change while this lock is held. The many list and the 88 * multi-hop list are both protected by rdc_many_lock. 89 */ 90 kmutex_t rdc_conf_lock; 91 kmutex_t rdc_many_lock; /* Many/multi-list lock */ 92 93 static kmutex_t rdc_net_hnd_id_lock; /* Network handle id lock */ 94 int rdc_debug = 0; 95 int rdc_debug_sleep = 0; 96 97 static int rdc_net_hnd_id = 1; 98 99 extern kmutex_t rdc_clnt_lock; 100 101 static void rdc_ditemsfree(rdc_net_dataset_t *); 102 void rdc_clnt_destroy(void); 103 104 rdc_k_info_t *rdc_k_info; 105 rdc_u_info_t *rdc_u_info; 106 107 unsigned long rdc_async_timeout; 108 109 nsc_size_t rdc_maxthres_queue = RDC_MAXTHRES_QUEUE; 110 int rdc_max_qitems = RDC_MAX_QITEMS; 111 int rdc_asyncthr = RDC_ASYNCTHR; 112 static nsc_svc_t *rdc_volume_update; 113 static int rdc_prealloc_handle = 1; 114 115 extern int _rdc_rsrv_diskq(rdc_group_t *group); 116 extern void _rdc_rlse_diskq(rdc_group_t *group); 117 118 /* 119 * Forward declare all statics that are used before defined 120 * to enforce parameter checking 121 * 122 * Some (if not all) of these could be removed if the code were reordered 123 */ 124 125 static void rdc_volume_update_svc(intptr_t); 126 static void halt_sync(rdc_k_info_t *krdc); 127 void rdc_kstat_create(int index); 128 void rdc_kstat_delete(int index); 129 static int rdc_checkforbitmap(int, nsc_off_t); 130 static int rdc_installbitmap(int, void *, int, nsc_off_t, int, int *, int); 131 static rdc_group_t *rdc_newgroup(); 132 133 int rdc_enable_diskq(rdc_k_info_t *krdc); 134 void rdc_close_diskq(rdc_group_t *group); 135 int rdc_suspend_diskq(rdc_k_info_t *krdc); 136 int rdc_resume_diskq(rdc_k_info_t *krdc); 137 void rdc_init_diskq_header(rdc_group_t *grp, dqheader *header); 138 void rdc_fail_diskq(rdc_k_info_t *krdc, int wait, int dolog); 139 void rdc_unfail_diskq(rdc_k_info_t *krdc); 140 void rdc_unintercept_diskq(rdc_group_t *grp); 141 int rdc_stamp_diskq(rdc_k_info_t *krdc, int rsrvd, int flags); 142 void rdc_qfiller_thr(rdc_k_info_t *krdc); 143 144 nstset_t *_rdc_ioset; 145 nstset_t *_rdc_flset; 146 147 /* 148 * RDC threadset tunables 149 */ 150 int rdc_threads = 64; /* default number of threads */ 151 int rdc_threads_inc = 8; /* increment for changing the size of the set */ 152 153 /* 154 * Private threadset manipulation variables 155 */ 156 static int rdc_threads_hysteresis = 2; 157 /* hysteresis for threadset resizing */ 158 static int rdc_sets_active; /* number of sets currently enabled */ 159 160 #ifdef DEBUG 161 kmutex_t rdc_cntlock; 162 #endif 163 164 /* 165 * rdc_thread_deconfigure - rdc is being deconfigured, stop any 166 * thread activity. 167 * 168 * Inherently single-threaded by the Solaris module unloading code. 169 */ 170 static void 171 rdc_thread_deconfigure(void) 172 { 173 nst_destroy(_rdc_ioset); 174 _rdc_ioset = NULL; 175 176 nst_destroy(_rdc_flset); 177 _rdc_flset = NULL; 178 179 nst_destroy(sync_info.rdc_syncset); 180 sync_info.rdc_syncset = NULL; 181 } 182 183 /* 184 * rdc_thread_configure - rdc is being configured, initialize the 185 * threads we need for flushing aync volumes. 186 * 187 * Must be called with rdc_conf_lock held. 188 */ 189 static int 190 rdc_thread_configure(void) 191 { 192 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 193 194 if ((_rdc_ioset = nst_init("rdc_thr", rdc_threads)) == NULL) 195 return (EINVAL); 196 197 if ((_rdc_flset = nst_init("rdc_flushthr", 2)) == NULL) 198 return (EINVAL); 199 200 if ((sync_info.rdc_syncset = 201 nst_init("rdc_syncthr", RDC_MAX_SYNC_THREADS)) == NULL) 202 return (EINVAL); 203 204 return (0); 205 } 206 207 208 /* 209 * rdc_thread_tune - called to tune the size of the rdc threadset. 210 * 211 * Called from the config code when an rdc_set has been enabled or disabled. 212 * 'sets' is the increment to the number of active rdc_sets. 213 * 214 * Must be called with rdc_conf_lock held. 215 */ 216 static void 217 rdc_thread_tune(int sets) 218 { 219 int incr = (sets > 0) ? 1 : -1; 220 int change = 0; 221 int nthreads; 222 223 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 224 225 if (sets < 0) 226 sets = -sets; 227 228 while (sets--) { 229 nthreads = nst_nthread(_rdc_ioset); 230 rdc_sets_active += incr; 231 232 if (rdc_sets_active >= nthreads) 233 change += nst_add_thread(_rdc_ioset, rdc_threads_inc); 234 else if ((rdc_sets_active < 235 (nthreads - (rdc_threads_inc + rdc_threads_hysteresis))) && 236 ((nthreads - rdc_threads_inc) >= rdc_threads)) 237 change -= nst_del_thread(_rdc_ioset, rdc_threads_inc); 238 } 239 240 #ifdef DEBUG 241 if (change) { 242 cmn_err(CE_NOTE, "!rdc_thread_tune: " 243 "nsets %d, nthreads %d, nthreads change %d", 244 rdc_sets_active, nst_nthread(_rdc_ioset), change); 245 } 246 #endif 247 } 248 249 250 /* 251 * _rdc_unload() - cache is being unloaded, 252 * deallocate any dual copy structures allocated during cache 253 * loading. 254 */ 255 void 256 _rdc_unload(void) 257 { 258 int i; 259 rdc_k_info_t *krdc; 260 261 if (rdc_volume_update) { 262 (void) nsc_unregister_svc(rdc_volume_update); 263 rdc_volume_update = NULL; 264 } 265 266 rdc_thread_deconfigure(); 267 268 if (rdc_k_info != NULL) { 269 for (i = 0; i < rdc_max_sets; i++) { 270 krdc = &rdc_k_info[i]; 271 mutex_destroy(&krdc->dc_sleep); 272 mutex_destroy(&krdc->bmapmutex); 273 mutex_destroy(&krdc->kstat_mutex); 274 mutex_destroy(&krdc->bmp_kstat_mutex); 275 mutex_destroy(&krdc->syncbitmutex); 276 cv_destroy(&krdc->busycv); 277 cv_destroy(&krdc->closingcv); 278 cv_destroy(&krdc->haltcv); 279 cv_destroy(&krdc->synccv); 280 } 281 } 282 283 mutex_destroy(&sync_info.lock); 284 mutex_destroy(&rdc_ping_lock); 285 mutex_destroy(&net_blk_lock); 286 mutex_destroy(&rdc_conf_lock); 287 mutex_destroy(&rdc_many_lock); 288 mutex_destroy(&rdc_net_hnd_id_lock); 289 mutex_destroy(&rdc_clnt_lock); 290 #ifdef DEBUG 291 mutex_destroy(&rdc_cntlock); 292 #endif 293 net_exit = ATM_EXIT; 294 295 if (rdc_k_info != NULL) 296 kmem_free(rdc_k_info, sizeof (*rdc_k_info) * rdc_max_sets); 297 if (rdc_u_info != NULL) 298 kmem_free(rdc_u_info, sizeof (*rdc_u_info) * rdc_max_sets); 299 rdc_k_info = NULL; 300 rdc_u_info = NULL; 301 rdc_max_sets = 0; 302 } 303 304 305 /* 306 * _rdc_load() - rdc is being loaded, Allocate anything 307 * that will be needed while the cache is loaded but doesn't really 308 * depend on configuration parameters. 309 * 310 */ 311 int 312 _rdc_load(void) 313 { 314 int i; 315 rdc_k_info_t *krdc; 316 317 mutex_init(&rdc_ping_lock, NULL, MUTEX_DRIVER, NULL); 318 mutex_init(&net_blk_lock, NULL, MUTEX_DRIVER, NULL); 319 mutex_init(&rdc_conf_lock, NULL, MUTEX_DRIVER, NULL); 320 mutex_init(&rdc_many_lock, NULL, MUTEX_DRIVER, NULL); 321 mutex_init(&rdc_net_hnd_id_lock, NULL, MUTEX_DRIVER, NULL); 322 mutex_init(&rdc_clnt_lock, NULL, MUTEX_DRIVER, NULL); 323 mutex_init(&sync_info.lock, NULL, MUTEX_DRIVER, NULL); 324 325 #ifdef DEBUG 326 mutex_init(&rdc_cntlock, NULL, MUTEX_DRIVER, NULL); 327 #endif 328 329 if ((i = nsc_max_devices()) < rdc_max_sets) 330 rdc_max_sets = i; 331 /* following case for partial installs that may fail */ 332 if (!rdc_max_sets) 333 rdc_max_sets = 1024; 334 335 rdc_k_info = kmem_zalloc(sizeof (*rdc_k_info) * rdc_max_sets, KM_SLEEP); 336 337 rdc_u_info = kmem_zalloc(sizeof (*rdc_u_info) * rdc_max_sets, KM_SLEEP); 338 339 net_exit = ATM_NONE; 340 for (i = 0; i < rdc_max_sets; i++) { 341 krdc = &rdc_k_info[i]; 342 bzero(krdc, sizeof (*krdc)); 343 krdc->index = i; 344 mutex_init(&krdc->dc_sleep, NULL, MUTEX_DRIVER, NULL); 345 mutex_init(&krdc->bmapmutex, NULL, MUTEX_DRIVER, NULL); 346 mutex_init(&krdc->kstat_mutex, NULL, MUTEX_DRIVER, NULL); 347 mutex_init(&krdc->bmp_kstat_mutex, NULL, MUTEX_DRIVER, NULL); 348 mutex_init(&krdc->syncbitmutex, NULL, MUTEX_DRIVER, NULL); 349 cv_init(&krdc->busycv, NULL, CV_DRIVER, NULL); 350 cv_init(&krdc->closingcv, NULL, CV_DRIVER, NULL); 351 cv_init(&krdc->haltcv, NULL, CV_DRIVER, NULL); 352 cv_init(&krdc->synccv, NULL, CV_DRIVER, NULL); 353 } 354 355 rdc_volume_update = nsc_register_svc("RDCVolumeUpdated", 356 rdc_volume_update_svc); 357 358 return (0); 359 } 360 361 static void 362 rdc_u_init(rdc_u_info_t *urdc) 363 { 364 const int index = (int)(urdc - &rdc_u_info[0]); 365 366 if (urdc->secondary.addr.maxlen) 367 free_rdc_netbuf(&urdc->secondary.addr); 368 if (urdc->primary.addr.maxlen) 369 free_rdc_netbuf(&urdc->primary.addr); 370 371 bzero(urdc, sizeof (rdc_u_info_t)); 372 373 urdc->index = index; 374 urdc->maxqfbas = rdc_maxthres_queue; 375 urdc->maxqitems = rdc_max_qitems; 376 urdc->asyncthr = rdc_asyncthr; 377 } 378 379 /* 380 * _rdc_configure() - cache is being configured. 381 * 382 * Initialize dual copy structures 383 */ 384 int 385 _rdc_configure(void) 386 { 387 int index; 388 rdc_k_info_t *krdc; 389 390 for (index = 0; index < rdc_max_sets; index++) { 391 krdc = &rdc_k_info[index]; 392 393 krdc->remote_index = -1; 394 krdc->dcio_bitmap = NULL; 395 krdc->bitmap_ref = NULL; 396 krdc->bitmap_size = 0; 397 krdc->bitmap_write = 0; 398 krdc->disk_status = 0; 399 krdc->many_next = krdc; 400 401 rdc_u_init(&rdc_u_info[index]); 402 } 403 404 rdc_async_timeout = 120 * HZ; /* Seconds * HZ */ 405 MAX_RDC_FBAS = FBA_LEN(RDC_MAXDATA); 406 if (net_exit != ATM_INIT) { 407 net_exit = ATM_INIT; 408 return (0); 409 } 410 return (0); 411 } 412 413 /* 414 * _rdc_deconfigure - rdc is being deconfigured, shut down any 415 * dual copy operations and return to an unconfigured state. 416 */ 417 void 418 _rdc_deconfigure(void) 419 { 420 rdc_k_info_t *krdc; 421 rdc_u_info_t *urdc; 422 int index; 423 424 for (index = 0; index < rdc_max_sets; index++) { 425 krdc = &rdc_k_info[index]; 426 urdc = &rdc_u_info[index]; 427 428 krdc->remote_index = -1; 429 krdc->dcio_bitmap = NULL; 430 krdc->bitmap_ref = NULL; 431 krdc->bitmap_size = 0; 432 krdc->bitmap_write = 0; 433 krdc->disk_status = 0; 434 krdc->many_next = krdc; 435 436 if (urdc->primary.addr.maxlen) 437 free_rdc_netbuf(&(urdc->primary.addr)); 438 439 if (urdc->secondary.addr.maxlen) 440 free_rdc_netbuf(&(urdc->secondary.addr)); 441 442 bzero(urdc, sizeof (rdc_u_info_t)); 443 urdc->index = index; 444 } 445 net_exit = ATM_EXIT; 446 rdc_clnt_destroy(); 447 448 } 449 450 451 /* 452 * Lock primitives, containing checks that lock ordering isn't broken 453 */ 454 /*ARGSUSED*/ 455 void 456 rdc_many_enter(rdc_k_info_t *krdc) 457 { 458 ASSERT(!MUTEX_HELD(&krdc->bmapmutex)); 459 460 mutex_enter(&rdc_many_lock); 461 } 462 463 /* ARGSUSED */ 464 void 465 rdc_many_exit(rdc_k_info_t *krdc) 466 { 467 mutex_exit(&rdc_many_lock); 468 } 469 470 void 471 rdc_group_enter(rdc_k_info_t *krdc) 472 { 473 ASSERT(!MUTEX_HELD(&rdc_many_lock)); 474 ASSERT(!MUTEX_HELD(&rdc_conf_lock)); 475 ASSERT(!MUTEX_HELD(&krdc->bmapmutex)); 476 477 mutex_enter(&krdc->group->lock); 478 } 479 480 void 481 rdc_group_exit(rdc_k_info_t *krdc) 482 { 483 mutex_exit(&krdc->group->lock); 484 } 485 486 /* 487 * Suspend and disable operations use this function to wait until it is safe 488 * to do continue, without trashing data structures used by other ioctls. 489 */ 490 static void 491 wait_busy(rdc_k_info_t *krdc) 492 { 493 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 494 495 while (krdc->busy_count > 0) 496 cv_wait(&krdc->busycv, &rdc_conf_lock); 497 } 498 499 500 /* 501 * Other ioctls use this function to hold off disable and suspend. 502 */ 503 void 504 set_busy(rdc_k_info_t *krdc) 505 { 506 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 507 508 wait_busy(krdc); 509 510 krdc->busy_count++; 511 } 512 513 514 /* 515 * Other ioctls use this function to allow disable and suspend to continue. 516 */ 517 void 518 wakeup_busy(rdc_k_info_t *krdc) 519 { 520 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 521 522 if (krdc->busy_count <= 0) 523 return; 524 525 krdc->busy_count--; 526 cv_broadcast(&krdc->busycv); 527 } 528 529 530 /* 531 * Remove the rdc set from its group, and destroy the group if no longer in 532 * use. 533 */ 534 static void 535 remove_from_group(rdc_k_info_t *krdc) 536 { 537 rdc_k_info_t *p; 538 rdc_group_t *group; 539 540 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 541 542 rdc_many_enter(krdc); 543 group = krdc->group; 544 545 group->count--; 546 547 /* 548 * lock queue while looking at thrnum 549 */ 550 mutex_enter(&group->ra_queue.net_qlock); 551 if ((group->rdc_thrnum == 0) && (group->count == 0)) { 552 553 /* 554 * Assure the we've stopped and the flusher thread has not 555 * fallen back to sleep 556 */ 557 if (krdc->group->ra_queue.qfill_sleeping != RDC_QFILL_DEAD) { 558 group->ra_queue.qfflags |= RDC_QFILLSTOP; 559 while (krdc->group->ra_queue.qfflags & RDC_QFILLSTOP) { 560 if (krdc->group->ra_queue.qfill_sleeping == 561 RDC_QFILL_ASLEEP) 562 cv_broadcast(&group->ra_queue.qfcv); 563 mutex_exit(&group->ra_queue.net_qlock); 564 delay(2); 565 mutex_enter(&group->ra_queue.net_qlock); 566 } 567 } 568 mutex_exit(&group->ra_queue.net_qlock); 569 570 mutex_enter(&group->diskqmutex); 571 rdc_close_diskq(group); 572 mutex_exit(&group->diskqmutex); 573 rdc_delgroup(group); 574 rdc_many_exit(krdc); 575 krdc->group = NULL; 576 return; 577 } 578 mutex_exit(&group->ra_queue.net_qlock); 579 /* 580 * Always clear the group field. 581 * no, you need it set in rdc_flush_memq(). 582 * to call rdc_group_log() 583 * krdc->group = NULL; 584 */ 585 586 /* Take this rdc structure off the group list */ 587 588 for (p = krdc->group_next; p->group_next != krdc; p = p->group_next) 589 ; 590 p->group_next = krdc->group_next; 591 592 rdc_many_exit(krdc); 593 } 594 595 596 /* 597 * Add the rdc set to its group, setting up a new group if it's the first one. 598 */ 599 static int 600 add_to_group(rdc_k_info_t *krdc, int options, int cmd) 601 { 602 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 603 rdc_u_info_t *utmp; 604 rdc_k_info_t *ktmp; 605 int index; 606 rdc_group_t *group; 607 int rc = 0; 608 nsthread_t *trc; 609 610 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 611 612 /* 613 * Look for matching group name, primary host name and secondary 614 * host name. 615 */ 616 617 rdc_many_enter(krdc); 618 for (index = 0; index < rdc_max_sets; index++) { 619 utmp = &rdc_u_info[index]; 620 ktmp = &rdc_k_info[index]; 621 622 if (urdc->group_name[0] == 0) 623 break; 624 625 if (!IS_CONFIGURED(ktmp)) 626 continue; 627 628 if (strncmp(utmp->group_name, urdc->group_name, 629 NSC_MAXPATH) != 0) 630 continue; 631 if (strncmp(utmp->primary.intf, urdc->primary.intf, 632 MAX_RDC_HOST_SIZE) != 0) { 633 /* Same group name, different primary interface */ 634 rdc_many_exit(krdc); 635 return (-1); 636 } 637 if (strncmp(utmp->secondary.intf, urdc->secondary.intf, 638 MAX_RDC_HOST_SIZE) != 0) { 639 /* Same group name, different secondary interface */ 640 rdc_many_exit(krdc); 641 return (-1); 642 } 643 644 /* Group already exists, so add this set to the group */ 645 646 if (((options & RDC_OPT_ASYNC) == 0) && 647 ((ktmp->type_flag & RDC_ASYNCMODE) != 0)) { 648 /* Must be same mode as existing group members */ 649 rdc_many_exit(krdc); 650 return (-1); 651 } 652 if (((options & RDC_OPT_ASYNC) != 0) && 653 ((ktmp->type_flag & RDC_ASYNCMODE) == 0)) { 654 /* Must be same mode as existing group members */ 655 rdc_many_exit(krdc); 656 return (-1); 657 } 658 659 /* cannont reconfigure existing group into new queue this way */ 660 if ((cmd != RDC_CMD_RESUME) && 661 !RDC_IS_DISKQ(ktmp->group) && urdc->disk_queue[0] != '\0') { 662 rdc_many_exit(krdc); 663 return (RDC_EQNOADD); 664 } 665 666 ktmp->group->count++; 667 krdc->group = ktmp->group; 668 krdc->group_next = ktmp->group_next; 669 ktmp->group_next = krdc; 670 671 urdc->autosync = utmp->autosync; /* Same as rest */ 672 673 (void) strncpy(urdc->disk_queue, utmp->disk_queue, NSC_MAXPATH); 674 675 rdc_many_exit(krdc); 676 return (0); 677 } 678 679 /* This must be a new group */ 680 group = rdc_newgroup(); 681 krdc->group = group; 682 krdc->group_next = krdc; 683 urdc->autosync = -1; /* Unknown */ 684 685 /* 686 * Tune the thread set by one for each thread created 687 */ 688 rdc_thread_tune(1); 689 690 trc = nst_create(_rdc_ioset, rdc_qfiller_thr, (void *)krdc, NST_SLEEP); 691 if (trc == NULL) { 692 rc = -1; 693 cmn_err(CE_NOTE, "!unable to create queue filler daemon"); 694 goto fail; 695 } 696 697 if (urdc->disk_queue[0] == '\0') { 698 krdc->group->flags |= RDC_MEMQUE; 699 } else { 700 krdc->group->flags |= RDC_DISKQUE; 701 702 /* XXX check here for resume or enable and act accordingly */ 703 704 if (cmd == RDC_CMD_RESUME) { 705 rc = rdc_resume_diskq(krdc); 706 707 } else if (cmd == RDC_CMD_ENABLE) { 708 rc = rdc_enable_diskq(krdc); 709 if ((rc == RDC_EQNOADD) && (cmd != RDC_CMD_ENABLE)) { 710 cmn_err(CE_WARN, "!disk queue %s enable failed," 711 " enabling memory queue", 712 urdc->disk_queue); 713 krdc->group->flags &= ~RDC_DISKQUE; 714 krdc->group->flags |= RDC_MEMQUE; 715 bzero(urdc->disk_queue, NSC_MAXPATH); 716 } 717 } 718 } 719 fail: 720 rdc_many_exit(krdc); 721 return (rc); 722 } 723 724 725 /* 726 * Move the set to a new group if possible 727 */ 728 static int 729 change_group(rdc_k_info_t *krdc, int options) 730 { 731 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 732 rdc_u_info_t *utmp; 733 rdc_k_info_t *ktmp; 734 rdc_k_info_t *next; 735 char tmpq[NSC_MAXPATH]; 736 int index; 737 int rc = -1; 738 rdc_group_t *group, *old_group; 739 nsthread_t *trc; 740 741 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 742 743 /* 744 * Look for matching group name, primary host name and secondary 745 * host name. 746 */ 747 748 bzero(&tmpq, sizeof (tmpq)); 749 rdc_many_enter(krdc); 750 751 old_group = krdc->group; 752 next = krdc->group_next; 753 754 if (RDC_IS_DISKQ(old_group)) { /* can't keep your own queue */ 755 (void) strncpy(tmpq, urdc->disk_queue, NSC_MAXPATH); 756 bzero(urdc->disk_queue, sizeof (urdc->disk_queue)); 757 } 758 for (index = 0; index < rdc_max_sets; index++) { 759 utmp = &rdc_u_info[index]; 760 ktmp = &rdc_k_info[index]; 761 762 if (ktmp == krdc) 763 continue; 764 765 if (urdc->group_name[0] == 0) 766 break; 767 768 if (!IS_CONFIGURED(ktmp)) 769 continue; 770 771 if (strncmp(utmp->group_name, urdc->group_name, 772 NSC_MAXPATH) != 0) 773 continue; 774 if (strncmp(utmp->primary.intf, urdc->primary.intf, 775 MAX_RDC_HOST_SIZE) != 0) 776 goto bad; 777 if (strncmp(utmp->secondary.intf, urdc->secondary.intf, 778 MAX_RDC_HOST_SIZE) != 0) 779 goto bad; 780 781 /* Group already exists, so add this set to the group */ 782 783 if (((options & RDC_OPT_ASYNC) == 0) && 784 ((ktmp->type_flag & RDC_ASYNCMODE) != 0)) { 785 /* Must be same mode as existing group members */ 786 goto bad; 787 } 788 if (((options & RDC_OPT_ASYNC) != 0) && 789 ((ktmp->type_flag & RDC_ASYNCMODE) == 0)) { 790 /* Must be same mode as existing group members */ 791 goto bad; 792 } 793 794 ktmp->group->count++; 795 krdc->group = ktmp->group; 796 krdc->group_next = ktmp->group_next; 797 ktmp->group_next = krdc; 798 bzero(urdc->disk_queue, sizeof (urdc->disk_queue)); 799 (void) strncpy(urdc->disk_queue, utmp->disk_queue, NSC_MAXPATH); 800 801 goto good; 802 } 803 804 /* This must be a new group */ 805 group = rdc_newgroup(); 806 krdc->group = group; 807 krdc->group_next = krdc; 808 809 trc = nst_create(_rdc_ioset, rdc_qfiller_thr, (void *)krdc, NST_SLEEP); 810 if (trc == NULL) { 811 rc = -1; 812 cmn_err(CE_NOTE, "!unable to create queue filler daemon"); 813 goto bad; 814 } 815 816 if (urdc->disk_queue[0] == 0) { 817 krdc->group->flags |= RDC_MEMQUE; 818 } else { 819 krdc->group->flags |= RDC_DISKQUE; 820 if ((rc = rdc_enable_diskq(krdc)) < 0) 821 goto bad; 822 } 823 good: 824 if (options & RDC_OPT_ASYNC) { 825 krdc->type_flag |= RDC_ASYNCMODE; 826 rdc_set_flags(urdc, RDC_ASYNC); 827 } else { 828 krdc->type_flag &= ~RDC_ASYNCMODE; 829 rdc_clr_flags(urdc, RDC_ASYNC); 830 } 831 832 old_group->count--; 833 if (!old_group->rdc_writer && old_group->count == 0) { 834 /* Group now empty, so destroy */ 835 if (RDC_IS_DISKQ(old_group)) { 836 rdc_unintercept_diskq(old_group); 837 mutex_enter(&old_group->diskqmutex); 838 rdc_close_diskq(old_group); 839 mutex_exit(&old_group->diskqmutex); 840 } 841 842 mutex_enter(&old_group->ra_queue.net_qlock); 843 844 /* 845 * Assure the we've stopped and the flusher thread has not 846 * fallen back to sleep 847 */ 848 if (old_group->ra_queue.qfill_sleeping != RDC_QFILL_DEAD) { 849 old_group->ra_queue.qfflags |= RDC_QFILLSTOP; 850 while (old_group->ra_queue.qfflags & RDC_QFILLSTOP) { 851 if (old_group->ra_queue.qfill_sleeping == 852 RDC_QFILL_ASLEEP) 853 cv_broadcast(&old_group->ra_queue.qfcv); 854 mutex_exit(&old_group->ra_queue.net_qlock); 855 delay(2); 856 mutex_enter(&old_group->ra_queue.net_qlock); 857 } 858 } 859 mutex_exit(&old_group->ra_queue.net_qlock); 860 861 rdc_delgroup(old_group); 862 rdc_many_exit(krdc); 863 return (0); 864 } 865 866 /* Take this rdc structure off the old group list */ 867 868 for (ktmp = next; ktmp->group_next != krdc; ktmp = ktmp->group_next) 869 ; 870 ktmp->group_next = next; 871 872 rdc_many_exit(krdc); 873 return (0); 874 875 bad: 876 /* Leave existing group status alone */ 877 (void) strncpy(urdc->disk_queue, tmpq, NSC_MAXPATH); 878 rdc_many_exit(krdc); 879 return (rc); 880 } 881 882 883 /* 884 * Set flags for an rdc set, setting the group flags as necessary. 885 */ 886 void 887 rdc_set_flags(rdc_u_info_t *urdc, int flags) 888 { 889 rdc_k_info_t *krdc = &rdc_k_info[urdc->index]; 890 int vflags, sflags, bflags, ssflags; 891 892 DTRACE_PROBE2(rdc_set_flags, int, krdc->index, int, flags); 893 vflags = flags & RDC_VFLAGS; 894 sflags = flags & RDC_SFLAGS; 895 bflags = flags & RDC_BFLAGS; 896 ssflags = flags & RDC_SYNC_STATE_FLAGS; 897 898 if (vflags) { 899 /* normal volume flags */ 900 ASSERT(MUTEX_HELD(&rdc_conf_lock) || 901 MUTEX_HELD(&krdc->group->lock)); 902 if (ssflags) 903 mutex_enter(&krdc->bmapmutex); 904 905 urdc->flags |= vflags; 906 907 if (ssflags) 908 mutex_exit(&krdc->bmapmutex); 909 } 910 911 if (sflags) { 912 /* Sync state flags that are protected by a different lock */ 913 ASSERT(MUTEX_HELD(&rdc_many_lock)); 914 urdc->sync_flags |= sflags; 915 } 916 917 if (bflags) { 918 /* Bmap state flags that are protected by a different lock */ 919 ASSERT(MUTEX_HELD(&krdc->bmapmutex)); 920 urdc->bmap_flags |= bflags; 921 } 922 923 } 924 925 926 /* 927 * Clear flags for an rdc set, clearing the group flags as necessary. 928 */ 929 void 930 rdc_clr_flags(rdc_u_info_t *urdc, int flags) 931 { 932 rdc_k_info_t *krdc = &rdc_k_info[urdc->index]; 933 int vflags, sflags, bflags; 934 935 DTRACE_PROBE2(rdc_clr_flags, int, krdc->index, int, flags); 936 vflags = flags & RDC_VFLAGS; 937 sflags = flags & RDC_SFLAGS; 938 bflags = flags & RDC_BFLAGS; 939 940 if (vflags) { 941 /* normal volume flags */ 942 ASSERT(MUTEX_HELD(&rdc_conf_lock) || 943 MUTEX_HELD(&krdc->group->lock)); 944 urdc->flags &= ~vflags; 945 946 } 947 948 if (sflags) { 949 /* Sync state flags that are protected by a different lock */ 950 ASSERT(MUTEX_HELD(&rdc_many_lock)); 951 urdc->sync_flags &= ~sflags; 952 } 953 954 if (bflags) { 955 /* Bmap state flags that are protected by a different lock */ 956 ASSERT(MUTEX_HELD(&krdc->bmapmutex)); 957 urdc->bmap_flags &= ~bflags; 958 } 959 } 960 961 962 /* 963 * Get the flags for an rdc set. 964 */ 965 int 966 rdc_get_vflags(rdc_u_info_t *urdc) 967 { 968 return (urdc->flags | urdc->sync_flags | urdc->bmap_flags); 969 } 970 971 972 /* 973 * Initialise flags for an rdc set. 974 */ 975 static void 976 rdc_init_flags(rdc_u_info_t *urdc) 977 { 978 urdc->flags = 0; 979 urdc->mflags = 0; 980 urdc->sync_flags = 0; 981 urdc->bmap_flags = 0; 982 } 983 984 985 /* 986 * Set flags for a many group. 987 */ 988 void 989 rdc_set_mflags(rdc_u_info_t *urdc, int flags) 990 { 991 rdc_k_info_t *krdc = &rdc_k_info[urdc->index]; 992 rdc_k_info_t *this = krdc; 993 994 ASSERT(!(flags & ~RDC_MFLAGS)); 995 996 if (flags == 0) 997 return; 998 999 ASSERT(MUTEX_HELD(&rdc_many_lock)); 1000 1001 rdc_set_flags(urdc, flags); /* set flags on local urdc */ 1002 1003 urdc->mflags |= flags; 1004 for (krdc = krdc->many_next; krdc != this; krdc = krdc->many_next) { 1005 urdc = &rdc_u_info[krdc->index]; 1006 if (!IS_ENABLED(urdc)) 1007 continue; 1008 urdc->mflags |= flags; 1009 } 1010 } 1011 1012 1013 /* 1014 * Clear flags for a many group. 1015 */ 1016 void 1017 rdc_clr_mflags(rdc_u_info_t *urdc, int flags) 1018 { 1019 rdc_k_info_t *krdc = &rdc_k_info[urdc->index]; 1020 rdc_k_info_t *this = krdc; 1021 rdc_u_info_t *utmp; 1022 1023 ASSERT(!(flags & ~RDC_MFLAGS)); 1024 1025 if (flags == 0) 1026 return; 1027 1028 ASSERT(MUTEX_HELD(&rdc_many_lock)); 1029 1030 rdc_clr_flags(urdc, flags); /* clear flags on local urdc */ 1031 1032 /* 1033 * We must maintain the mflags based on the set of flags for 1034 * all the urdc's that are chained up. 1035 */ 1036 1037 /* 1038 * First look through all the urdc's and remove bits from 1039 * the 'flags' variable that are in use elsewhere. 1040 */ 1041 1042 for (krdc = krdc->many_next; krdc != this; krdc = krdc->many_next) { 1043 utmp = &rdc_u_info[krdc->index]; 1044 if (!IS_ENABLED(utmp)) 1045 continue; 1046 flags &= ~(rdc_get_vflags(utmp) & RDC_MFLAGS); 1047 if (flags == 0) 1048 break; 1049 } 1050 1051 /* 1052 * Now clear flags as necessary. 1053 */ 1054 1055 if (flags != 0) { 1056 urdc->mflags &= ~flags; 1057 for (krdc = krdc->many_next; krdc != this; 1058 krdc = krdc->many_next) { 1059 utmp = &rdc_u_info[krdc->index]; 1060 if (!IS_ENABLED(utmp)) 1061 continue; 1062 utmp->mflags &= ~flags; 1063 } 1064 } 1065 } 1066 1067 1068 int 1069 rdc_get_mflags(rdc_u_info_t *urdc) 1070 { 1071 return (urdc->mflags); 1072 } 1073 1074 1075 void 1076 rdc_set_flags_log(rdc_u_info_t *urdc, int flags, char *why) 1077 { 1078 DTRACE_PROBE2(rdc_set_flags_log, int, urdc->index, int, flags); 1079 1080 rdc_set_flags(urdc, flags); 1081 1082 if (why == NULL) 1083 return; 1084 1085 if (flags & RDC_LOGGING) 1086 cmn_err(CE_NOTE, "!sndr: %s:%s entered logging mode: %s", 1087 urdc->secondary.intf, urdc->secondary.file, why); 1088 if (flags & RDC_VOL_FAILED) 1089 cmn_err(CE_NOTE, "!sndr: %s:%s volume failed: %s", 1090 urdc->secondary.intf, urdc->secondary.file, why); 1091 if (flags & RDC_BMP_FAILED) 1092 cmn_err(CE_NOTE, "!sndr: %s:%s bitmap failed: %s", 1093 urdc->secondary.intf, urdc->secondary.file, why); 1094 } 1095 /* 1096 * rdc_lor(source, dest, len) 1097 * logically OR memory pointed to by source and dest, copying result into dest. 1098 */ 1099 void 1100 rdc_lor(const uchar_t *source, uchar_t *dest, int len) 1101 { 1102 int i; 1103 1104 if (source == NULL) 1105 return; 1106 1107 for (i = 0; i < len; i++) 1108 *dest++ |= *source++; 1109 } 1110 1111 1112 static int 1113 check_filesize(int index, spcs_s_info_t kstatus) 1114 { 1115 uint64_t remote_size; 1116 char tmp1[16], tmp2[16]; 1117 rdc_u_info_t *urdc = &rdc_u_info[index]; 1118 int status; 1119 1120 status = rdc_net_getsize(index, &remote_size); 1121 if (status) { 1122 (void) spcs_s_inttostring(status, tmp1, sizeof (tmp1), 0); 1123 spcs_s_add(kstatus, RDC_EGETSIZE, urdc->secondary.intf, 1124 urdc->secondary.file, tmp1); 1125 (void) rdc_net_state(index, CCIO_ENABLELOG); 1126 return (RDC_EGETSIZE); 1127 } 1128 if (remote_size < (unsigned long long)urdc->volume_size) { 1129 (void) spcs_s_inttostring( 1130 urdc->volume_size, tmp1, sizeof (tmp1), 0); 1131 /* 1132 * Cheat, and covert to int, until we have 1133 * spcs_s_unsignedlonginttostring(). 1134 */ 1135 status = (int)remote_size; 1136 (void) spcs_s_inttostring(status, tmp2, sizeof (tmp2), 0); 1137 spcs_s_add(kstatus, RDC_ESIZE, urdc->primary.intf, 1138 urdc->primary.file, tmp1, urdc->secondary.intf, 1139 urdc->secondary.file, tmp2); 1140 (void) rdc_net_state(index, CCIO_ENABLELOG); 1141 return (RDC_ESIZE); 1142 } 1143 return (0); 1144 } 1145 1146 1147 static void 1148 rdc_volume_update_svc(intptr_t arg) 1149 { 1150 rdc_update_t *update = (rdc_update_t *)arg; 1151 rdc_k_info_t *krdc; 1152 rdc_k_info_t *this; 1153 rdc_u_info_t *urdc; 1154 struct net_bdata6 bd; 1155 int index; 1156 int rc; 1157 1158 #ifdef DEBUG_IIUPDATE 1159 cmn_err(CE_NOTE, "!SNDR received update request for %s", 1160 update->volume); 1161 #endif 1162 1163 if ((update->protocol != RDC_SVC_ONRETURN) && 1164 (update->protocol != RDC_SVC_VOL_ENABLED)) { 1165 /* don't understand what the client intends to do */ 1166 update->denied = 1; 1167 spcs_s_add(update->status, RDC_EVERSION); 1168 return; 1169 } 1170 1171 index = rdc_lookup_enabled(update->volume, 0); 1172 if (index < 0) 1173 return; 1174 1175 /* 1176 * warn II that this volume is in use by sndr so 1177 * II can validate the sizes of the master vs shadow 1178 * and avoid trouble later down the line with 1179 * size mis-matches between urdc->volume_size and 1180 * what is returned from nsc_partsize() which may 1181 * be the size of the master when replicating the shadow 1182 */ 1183 if (update->protocol == RDC_SVC_VOL_ENABLED) { 1184 if (index >= 0) 1185 update->denied = 1; 1186 return; 1187 } 1188 1189 krdc = &rdc_k_info[index]; 1190 urdc = &rdc_u_info[index]; 1191 this = krdc; 1192 1193 do { 1194 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) { 1195 #ifdef DEBUG_IIUPDATE 1196 cmn_err(CE_NOTE, "!SNDR refused update request for %s", 1197 update->volume); 1198 #endif 1199 update->denied = 1; 1200 spcs_s_add(update->status, RDC_EMIRRORUP); 1201 return; 1202 } 1203 /* 1->many - all must be logging */ 1204 if (IS_MANY(krdc) && IS_STATE(urdc, RDC_PRIMARY)) { 1205 rdc_many_enter(krdc); 1206 for (krdc = krdc->many_next; krdc != this; 1207 krdc = krdc->many_next) { 1208 urdc = &rdc_u_info[krdc->index]; 1209 if (!IS_ENABLED(urdc)) 1210 continue; 1211 break; 1212 } 1213 rdc_many_exit(krdc); 1214 } 1215 } while (krdc != this); 1216 1217 #ifdef DEBUG_IIUPDATE 1218 cmn_err(CE_NOTE, "!SNDR allowed update request for %s", update->volume); 1219 #endif 1220 urdc = &rdc_u_info[krdc->index]; 1221 do { 1222 1223 bd.size = min(krdc->bitmap_size, (nsc_size_t)update->size); 1224 bd.data.data_val = (char *)update->bitmap; 1225 bd.offset = 0; 1226 bd.cd = index; 1227 1228 if ((rc = RDC_OR_BITMAP(&bd)) != 0) { 1229 update->denied = 1; 1230 spcs_s_add(update->status, rc); 1231 return; 1232 } 1233 urdc = &rdc_u_info[index]; 1234 urdc->bits_set = RDC_COUNT_BITMAP(krdc); 1235 if (IS_MANY(krdc) && IS_STATE(urdc, RDC_PRIMARY)) { 1236 rdc_many_enter(krdc); 1237 for (krdc = krdc->many_next; krdc != this; 1238 krdc = krdc->many_next) { 1239 index = krdc->index; 1240 if (!IS_ENABLED(urdc)) 1241 continue; 1242 break; 1243 } 1244 rdc_many_exit(krdc); 1245 } 1246 } while (krdc != this); 1247 1248 1249 /* II (or something else) has updated us, so no need for a sync */ 1250 if (rdc_get_vflags(urdc) & (RDC_SYNC_NEEDED | RDC_RSYNC_NEEDED)) { 1251 rdc_many_enter(krdc); 1252 rdc_clr_flags(urdc, RDC_SYNC_NEEDED | RDC_RSYNC_NEEDED); 1253 rdc_many_exit(krdc); 1254 } 1255 1256 if (krdc->bitmap_write > 0) 1257 (void) rdc_write_bitmap(krdc); 1258 } 1259 1260 1261 /* 1262 * rdc_check() 1263 * 1264 * Return 0 if the set is configured, enabled and the supplied 1265 * addressing information matches the in-kernel config, otherwise 1266 * return 1. 1267 */ 1268 static int 1269 rdc_check(rdc_k_info_t *krdc, rdc_set_t *rdc_set) 1270 { 1271 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 1272 1273 ASSERT(MUTEX_HELD(&krdc->group->lock)); 1274 1275 if (!IS_ENABLED(urdc)) 1276 return (1); 1277 1278 if (strncmp(urdc->primary.file, rdc_set->primary.file, 1279 NSC_MAXPATH) != 0) { 1280 #ifdef DEBUG 1281 cmn_err(CE_WARN, "!rdc_check: primary file mismatch %s vs %s", 1282 urdc->primary.file, rdc_set->primary.file); 1283 #endif 1284 return (1); 1285 } 1286 1287 if (rdc_set->primary.addr.len != 0 && 1288 bcmp(urdc->primary.addr.buf, rdc_set->primary.addr.buf, 1289 urdc->primary.addr.len) != 0) { 1290 #ifdef DEBUG 1291 cmn_err(CE_WARN, "!rdc_check: primary address mismatch for %s", 1292 urdc->primary.file); 1293 #endif 1294 return (1); 1295 } 1296 1297 if (strncmp(urdc->secondary.file, rdc_set->secondary.file, 1298 NSC_MAXPATH) != 0) { 1299 #ifdef DEBUG 1300 cmn_err(CE_WARN, "!rdc_check: secondary file mismatch %s vs %s", 1301 urdc->secondary.file, rdc_set->secondary.file); 1302 #endif 1303 return (1); 1304 } 1305 1306 if (rdc_set->secondary.addr.len != 0 && 1307 bcmp(urdc->secondary.addr.buf, rdc_set->secondary.addr.buf, 1308 urdc->secondary.addr.len) != 0) { 1309 #ifdef DEBUG 1310 cmn_err(CE_WARN, "!rdc_check: secondary addr mismatch for %s", 1311 urdc->secondary.file); 1312 #endif 1313 return (1); 1314 } 1315 1316 return (0); 1317 } 1318 1319 1320 /* 1321 * Lookup enabled sets for a bitmap match 1322 */ 1323 1324 int 1325 rdc_lookup_bitmap(char *pathname) 1326 { 1327 rdc_u_info_t *urdc; 1328 #ifdef DEBUG 1329 rdc_k_info_t *krdc; 1330 #endif 1331 int index; 1332 1333 for (index = 0; index < rdc_max_sets; index++) { 1334 urdc = &rdc_u_info[index]; 1335 #ifdef DEBUG 1336 krdc = &rdc_k_info[index]; 1337 #endif 1338 ASSERT(krdc->index == index); 1339 ASSERT(urdc->index == index); 1340 1341 if (!IS_ENABLED(urdc)) 1342 continue; 1343 1344 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 1345 if (strncmp(pathname, urdc->primary.bitmap, 1346 NSC_MAXPATH) == 0) 1347 return (index); 1348 } else { 1349 if (strncmp(pathname, urdc->secondary.bitmap, 1350 NSC_MAXPATH) == 0) 1351 return (index); 1352 } 1353 } 1354 1355 return (-1); 1356 } 1357 1358 1359 /* 1360 * Translate a pathname to index into rdc_k_info[]. 1361 * Returns first match that is enabled. 1362 */ 1363 1364 int 1365 rdc_lookup_enabled(char *pathname, int allow_disabling) 1366 { 1367 rdc_u_info_t *urdc; 1368 rdc_k_info_t *krdc; 1369 int index; 1370 1371 restart: 1372 for (index = 0; index < rdc_max_sets; index++) { 1373 urdc = &rdc_u_info[index]; 1374 krdc = &rdc_k_info[index]; 1375 1376 ASSERT(krdc->index == index); 1377 ASSERT(urdc->index == index); 1378 1379 if (!IS_ENABLED(urdc)) 1380 continue; 1381 1382 if (allow_disabling == 0 && krdc->type_flag & RDC_UNREGISTER) 1383 continue; 1384 1385 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 1386 if (strncmp(pathname, urdc->primary.file, 1387 NSC_MAXPATH) == 0) 1388 return (index); 1389 } else { 1390 if (strncmp(pathname, urdc->secondary.file, 1391 NSC_MAXPATH) == 0) 1392 return (index); 1393 } 1394 } 1395 1396 if (allow_disabling == 0) { 1397 /* None found, or only a disabling one found, so try again */ 1398 allow_disabling = 1; 1399 goto restart; 1400 } 1401 1402 return (-1); 1403 } 1404 1405 1406 /* 1407 * Translate a pathname to index into rdc_k_info[]. 1408 * Returns first match that is configured. 1409 * 1410 * Used by enable & resume code. 1411 * Must be called with rdc_conf_lock held. 1412 */ 1413 1414 int 1415 rdc_lookup_configured(char *pathname) 1416 { 1417 rdc_u_info_t *urdc; 1418 rdc_k_info_t *krdc; 1419 int index; 1420 1421 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1422 1423 for (index = 0; index < rdc_max_sets; index++) { 1424 urdc = &rdc_u_info[index]; 1425 krdc = &rdc_k_info[index]; 1426 1427 ASSERT(krdc->index == index); 1428 ASSERT(urdc->index == index); 1429 1430 if (!IS_CONFIGURED(krdc)) 1431 continue; 1432 1433 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 1434 if (strncmp(pathname, urdc->primary.file, 1435 NSC_MAXPATH) == 0) 1436 return (index); 1437 } else { 1438 if (strncmp(pathname, urdc->secondary.file, 1439 NSC_MAXPATH) == 0) 1440 return (index); 1441 } 1442 } 1443 1444 return (-1); 1445 } 1446 1447 1448 /* 1449 * Looks up a configured set with matching secondary interface:volume 1450 * to check for illegal many-to-one volume configs. To be used during 1451 * enable and resume processing. 1452 * 1453 * Must be called with rdc_conf_lock held. 1454 */ 1455 1456 static int 1457 rdc_lookup_many2one(rdc_set_t *rdc_set) 1458 { 1459 rdc_u_info_t *urdc; 1460 rdc_k_info_t *krdc; 1461 int index; 1462 1463 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1464 1465 for (index = 0; index < rdc_max_sets; index++) { 1466 urdc = &rdc_u_info[index]; 1467 krdc = &rdc_k_info[index]; 1468 1469 if (!IS_CONFIGURED(krdc)) 1470 continue; 1471 1472 if (strncmp(urdc->secondary.file, 1473 rdc_set->secondary.file, NSC_MAXPATH) != 0) 1474 continue; 1475 if (strncmp(urdc->secondary.intf, 1476 rdc_set->secondary.intf, MAX_RDC_HOST_SIZE) != 0) 1477 continue; 1478 1479 break; 1480 } 1481 1482 if (index < rdc_max_sets) 1483 return (index); 1484 else 1485 return (-1); 1486 } 1487 1488 1489 /* 1490 * Looks up an rdc set to check if it is already configured, to be used from 1491 * functions called from the config ioctl where the interface names can be 1492 * used for comparison. 1493 * 1494 * Must be called with rdc_conf_lock held. 1495 */ 1496 1497 int 1498 rdc_lookup_byname(rdc_set_t *rdc_set) 1499 { 1500 rdc_u_info_t *urdc; 1501 rdc_k_info_t *krdc; 1502 int index; 1503 1504 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1505 1506 for (index = 0; index < rdc_max_sets; index++) { 1507 urdc = &rdc_u_info[index]; 1508 krdc = &rdc_k_info[index]; 1509 1510 ASSERT(krdc->index == index); 1511 ASSERT(urdc->index == index); 1512 1513 if (!IS_CONFIGURED(krdc)) 1514 continue; 1515 1516 if (strncmp(urdc->primary.file, rdc_set->primary.file, 1517 NSC_MAXPATH) != 0) 1518 continue; 1519 if (strncmp(urdc->primary.intf, rdc_set->primary.intf, 1520 MAX_RDC_HOST_SIZE) != 0) 1521 continue; 1522 if (strncmp(urdc->secondary.file, rdc_set->secondary.file, 1523 NSC_MAXPATH) != 0) 1524 continue; 1525 if (strncmp(urdc->secondary.intf, rdc_set->secondary.intf, 1526 MAX_RDC_HOST_SIZE) != 0) 1527 continue; 1528 1529 break; 1530 } 1531 1532 if (index < rdc_max_sets) 1533 return (index); 1534 else 1535 return (-1); 1536 } 1537 1538 /* 1539 * Looks up a secondary hostname and device, to be used from 1540 * functions called from the config ioctl where the interface names can be 1541 * used for comparison. 1542 * 1543 * Must be called with rdc_conf_lock held. 1544 */ 1545 1546 int 1547 rdc_lookup_byhostdev(char *intf, char *file) 1548 { 1549 rdc_u_info_t *urdc; 1550 rdc_k_info_t *krdc; 1551 int index; 1552 1553 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1554 1555 for (index = 0; index < rdc_max_sets; index++) { 1556 urdc = &rdc_u_info[index]; 1557 krdc = &rdc_k_info[index]; 1558 1559 ASSERT(krdc->index == index); 1560 ASSERT(urdc->index == index); 1561 1562 if (!IS_CONFIGURED(krdc)) 1563 continue; 1564 1565 if (strncmp(urdc->secondary.file, file, 1566 NSC_MAXPATH) != 0) 1567 continue; 1568 if (strncmp(urdc->secondary.intf, intf, 1569 MAX_RDC_HOST_SIZE) != 0) 1570 continue; 1571 break; 1572 } 1573 1574 if (index < rdc_max_sets) 1575 return (index); 1576 else 1577 return (-1); 1578 } 1579 1580 1581 /* 1582 * Looks up an rdc set to see if it is currently enabled, to be used on the 1583 * server so that the interface addresses must be used for comparison, as 1584 * the interface names may differ from those used on the client. 1585 * 1586 */ 1587 1588 int 1589 rdc_lookup_byaddr(rdc_set_t *rdc_set) 1590 { 1591 rdc_u_info_t *urdc; 1592 #ifdef DEBUG 1593 rdc_k_info_t *krdc; 1594 #endif 1595 int index; 1596 1597 for (index = 0; index < rdc_max_sets; index++) { 1598 urdc = &rdc_u_info[index]; 1599 #ifdef DEBUG 1600 krdc = &rdc_k_info[index]; 1601 #endif 1602 ASSERT(krdc->index == index); 1603 ASSERT(urdc->index == index); 1604 1605 if (!IS_ENABLED(urdc)) 1606 continue; 1607 1608 if (strcmp(urdc->primary.file, rdc_set->primary.file) != 0) 1609 continue; 1610 1611 if (strcmp(urdc->secondary.file, rdc_set->secondary.file) != 0) 1612 continue; 1613 1614 if (bcmp(urdc->primary.addr.buf, rdc_set->primary.addr.buf, 1615 urdc->primary.addr.len) != 0) { 1616 continue; 1617 } 1618 1619 if (bcmp(urdc->secondary.addr.buf, rdc_set->secondary.addr.buf, 1620 urdc->secondary.addr.len) != 0) { 1621 continue; 1622 } 1623 1624 break; 1625 } 1626 1627 if (index < rdc_max_sets) 1628 return (index); 1629 else 1630 return (-1); 1631 } 1632 1633 1634 /* 1635 * Return index of first multihop or 1-to-many 1636 * Behavior controlled by setting ismany. 1637 * ismany TRUE (one-to-many) 1638 * ismany FALSE (multihops) 1639 * 1640 */ 1641 static int 1642 rdc_lookup_multimany(rdc_k_info_t *krdc, const int ismany) 1643 { 1644 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 1645 rdc_u_info_t *utmp; 1646 rdc_k_info_t *ktmp; 1647 char *pathname; 1648 int index; 1649 int role; 1650 1651 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1652 ASSERT(MUTEX_HELD(&rdc_many_lock)); 1653 1654 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 1655 /* this host is the primary of the krdc set */ 1656 pathname = urdc->primary.file; 1657 if (ismany) { 1658 /* 1659 * 1-many sets are linked by primary : 1660 * look for matching primary on this host 1661 */ 1662 role = RDC_PRIMARY; 1663 } else { 1664 /* 1665 * multihop sets link primary to secondary : 1666 * look for matching secondary on this host 1667 */ 1668 role = 0; 1669 } 1670 } else { 1671 /* this host is the secondary of the krdc set */ 1672 pathname = urdc->secondary.file; 1673 if (ismany) { 1674 /* 1675 * 1-many sets are linked by primary, so if 1676 * this host is the secondary of the set this 1677 * cannot require 1-many linkage. 1678 */ 1679 return (-1); 1680 } else { 1681 /* 1682 * multihop sets link primary to secondary : 1683 * look for matching primary on this host 1684 */ 1685 role = RDC_PRIMARY; 1686 } 1687 } 1688 1689 for (index = 0; index < rdc_max_sets; index++) { 1690 utmp = &rdc_u_info[index]; 1691 ktmp = &rdc_k_info[index]; 1692 1693 if (!IS_CONFIGURED(ktmp)) { 1694 continue; 1695 } 1696 1697 if (role == RDC_PRIMARY) { 1698 /* 1699 * Find a primary that is this host and is not 1700 * krdc but shares the same data volume as krdc. 1701 */ 1702 if ((rdc_get_vflags(utmp) & RDC_PRIMARY) && 1703 strncmp(utmp->primary.file, pathname, 1704 NSC_MAXPATH) == 0 && (krdc != ktmp)) { 1705 break; 1706 } 1707 } else { 1708 /* 1709 * Find a secondary that is this host and is not 1710 * krdc but shares the same data volume as krdc. 1711 */ 1712 if (!(rdc_get_vflags(utmp) & RDC_PRIMARY) && 1713 strncmp(utmp->secondary.file, pathname, 1714 NSC_MAXPATH) == 0 && (krdc != ktmp)) { 1715 break; 1716 } 1717 } 1718 } 1719 1720 if (index < rdc_max_sets) 1721 return (index); 1722 else 1723 return (-1); 1724 } 1725 1726 /* 1727 * Returns secondary match that is configured. 1728 * 1729 * Used by enable & resume code. 1730 * Must be called with rdc_conf_lock held. 1731 */ 1732 1733 static int 1734 rdc_lookup_secondary(char *pathname) 1735 { 1736 rdc_u_info_t *urdc; 1737 rdc_k_info_t *krdc; 1738 int index; 1739 1740 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1741 1742 for (index = 0; index < rdc_max_sets; index++) { 1743 urdc = &rdc_u_info[index]; 1744 krdc = &rdc_k_info[index]; 1745 1746 ASSERT(krdc->index == index); 1747 ASSERT(urdc->index == index); 1748 1749 if (!IS_CONFIGURED(krdc)) 1750 continue; 1751 1752 if (!IS_STATE(urdc, RDC_PRIMARY)) { 1753 if (strncmp(pathname, urdc->secondary.file, 1754 NSC_MAXPATH) == 0) 1755 return (index); 1756 } 1757 } 1758 1759 return (-1); 1760 } 1761 1762 1763 static nsc_fd_t * 1764 rdc_open_direct(rdc_k_info_t *krdc) 1765 { 1766 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 1767 int rc; 1768 1769 if (krdc->remote_fd == NULL) 1770 krdc->remote_fd = nsc_open(urdc->direct_file, 1771 NSC_RDCHR_ID|NSC_DEVICE|NSC_RDWR, 0, 0, &rc); 1772 return (krdc->remote_fd); 1773 } 1774 1775 static void 1776 rdc_close_direct(rdc_k_info_t *krdc) 1777 { 1778 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 1779 1780 urdc->direct_file[0] = 0; 1781 if (krdc->remote_fd) { 1782 if (nsc_close(krdc->remote_fd) == 0) { 1783 krdc->remote_fd = NULL; 1784 } 1785 } 1786 } 1787 1788 1789 #ifdef DEBUG_MANY 1790 static void 1791 print_many(rdc_k_info_t *start) 1792 { 1793 rdc_k_info_t *p = start; 1794 rdc_u_info_t *q = &rdc_u_info[p->index]; 1795 1796 do { 1797 cmn_err(CE_CONT, "!krdc %p, %s %s (many_nxt %p multi_nxt %p)\n", 1798 p, q->primary.file, q->secondary.file, p->many_next, 1799 p->multi_next); 1800 delay(10); 1801 p = p->many_next; 1802 q = &rdc_u_info[p->index]; 1803 } while (p && p != start); 1804 } 1805 #endif /* DEBUG_MANY */ 1806 1807 1808 static int 1809 add_to_multi(rdc_k_info_t *krdc) 1810 { 1811 rdc_u_info_t *urdc; 1812 rdc_k_info_t *ktmp; 1813 rdc_u_info_t *utmp; 1814 int mindex; 1815 int domulti; 1816 1817 urdc = &rdc_u_info[krdc->index]; 1818 1819 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1820 ASSERT(MUTEX_HELD(&rdc_many_lock)); 1821 1822 /* Now find companion krdc */ 1823 mindex = rdc_lookup_multimany(krdc, FALSE); 1824 1825 #ifdef DEBUG_MANY 1826 cmn_err(CE_NOTE, 1827 "!add_to_multi: lookup_multimany: mindex %d prim %s sec %s", 1828 mindex, urdc->primary.file, urdc->secondary.file); 1829 #endif 1830 1831 if (mindex >= 0) { 1832 ktmp = &rdc_k_info[mindex]; 1833 utmp = &rdc_u_info[mindex]; 1834 1835 domulti = 1; 1836 1837 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && 1838 ktmp->multi_next != NULL) { 1839 /* 1840 * We are adding a new primary to a many 1841 * group that is the target of a multihop, just 1842 * ignore it since we are linked in elsewhere. 1843 */ 1844 domulti = 0; 1845 } 1846 1847 if (domulti) { 1848 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 1849 /* Is previous leg using direct file I/O? */ 1850 if (utmp->direct_file[0] != 0) { 1851 /* It is, so cannot proceed */ 1852 return (-1); 1853 } 1854 } else { 1855 /* Is this leg using direct file I/O? */ 1856 if (urdc->direct_file[0] != 0) { 1857 /* It is, so cannot proceed */ 1858 return (-1); 1859 } 1860 } 1861 krdc->multi_next = ktmp; 1862 ktmp->multi_next = krdc; 1863 } 1864 } else { 1865 krdc->multi_next = NULL; 1866 #ifdef DEBUG_MANY 1867 cmn_err(CE_NOTE, "!add_to_multi: NULL multi_next index %d", 1868 krdc->index); 1869 #endif 1870 } 1871 1872 return (0); 1873 } 1874 1875 1876 /* 1877 * Add a new set to the circular list of 1-to-many primaries and chain 1878 * up any multihop as well. 1879 */ 1880 static int 1881 add_to_many(rdc_k_info_t *krdc) 1882 { 1883 rdc_k_info_t *okrdc; 1884 int oindex; 1885 1886 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1887 1888 rdc_many_enter(krdc); 1889 1890 if (add_to_multi(krdc) < 0) { 1891 rdc_many_exit(krdc); 1892 return (-1); 1893 } 1894 1895 oindex = rdc_lookup_multimany(krdc, TRUE); 1896 if (oindex < 0) { 1897 #ifdef DEBUG_MANY 1898 print_many(krdc); 1899 #endif 1900 rdc_many_exit(krdc); 1901 return (0); 1902 } 1903 1904 okrdc = &rdc_k_info[oindex]; 1905 1906 #ifdef DEBUG_MANY 1907 print_many(okrdc); 1908 #endif 1909 krdc->many_next = okrdc->many_next; 1910 okrdc->many_next = krdc; 1911 1912 #ifdef DEBUG_MANY 1913 print_many(okrdc); 1914 #endif 1915 rdc_many_exit(krdc); 1916 return (0); 1917 } 1918 1919 1920 /* 1921 * Remove a set from the circular list of 1-to-many primaries. 1922 */ 1923 static void 1924 remove_from_many(rdc_k_info_t *old) 1925 { 1926 rdc_u_info_t *uold = &rdc_u_info[old->index]; 1927 rdc_k_info_t *p, *q; 1928 1929 ASSERT(MUTEX_HELD(&rdc_conf_lock)); 1930 1931 rdc_many_enter(old); 1932 1933 #ifdef DEBUG_MANY 1934 cmn_err(CE_NOTE, "!rdc: before remove_from_many"); 1935 print_many(old); 1936 #endif 1937 1938 if (old->many_next == old) { 1939 /* remove from multihop */ 1940 if ((q = old->multi_next) != NULL) { 1941 ASSERT(q->multi_next == old); 1942 q->multi_next = NULL; 1943 old->multi_next = NULL; 1944 } 1945 1946 rdc_many_exit(old); 1947 return; 1948 } 1949 1950 /* search */ 1951 for (p = old->many_next; p->many_next != old; p = p->many_next) 1952 ; 1953 1954 p->many_next = old->many_next; 1955 old->many_next = old; 1956 1957 if ((q = old->multi_next) != NULL) { 1958 /* 1959 * old was part of a multihop, so switch multi pointers 1960 * to someone remaining on the many chain 1961 */ 1962 ASSERT(p->multi_next == NULL); 1963 1964 q->multi_next = p; 1965 p->multi_next = q; 1966 old->multi_next = NULL; 1967 } 1968 1969 #ifdef DEBUG_MANY 1970 if (p == old) { 1971 cmn_err(CE_NOTE, "!rdc: after remove_from_many empty"); 1972 } else { 1973 cmn_err(CE_NOTE, "!rdc: after remove_from_many"); 1974 print_many(p); 1975 } 1976 #endif 1977 1978 rdc_clr_mflags(&rdc_u_info[p->index], 1979 (rdc_get_vflags(uold) & RDC_MFLAGS)); 1980 1981 rdc_many_exit(old); 1982 } 1983 1984 1985 static int 1986 _rdc_enable(rdc_set_t *rdc_set, int options, spcs_s_info_t kstatus) 1987 { 1988 int index; 1989 char *rhost; 1990 struct netbuf *addrp; 1991 rdc_k_info_t *krdc; 1992 rdc_u_info_t *urdc; 1993 rdc_srv_t *svp = NULL; 1994 char *local_file; 1995 char *local_bitmap; 1996 char *diskq; 1997 int rc; 1998 nsc_size_t maxfbas; 1999 rdc_group_t *grp; 2000 2001 if ((rdc_set->primary.intf[0] == 0) || 2002 (rdc_set->primary.addr.len == 0) || 2003 (rdc_set->primary.file[0] == 0) || 2004 (rdc_set->primary.bitmap[0] == 0) || 2005 (rdc_set->secondary.intf[0] == 0) || 2006 (rdc_set->secondary.addr.len == 0) || 2007 (rdc_set->secondary.file[0] == 0) || 2008 (rdc_set->secondary.bitmap[0] == 0)) { 2009 spcs_s_add(kstatus, RDC_EEMPTY); 2010 return (RDC_EEMPTY); 2011 } 2012 2013 /* Next check there aren't any enabled rdc sets which match. */ 2014 2015 mutex_enter(&rdc_conf_lock); 2016 2017 if (rdc_lookup_byname(rdc_set) >= 0) { 2018 mutex_exit(&rdc_conf_lock); 2019 spcs_s_add(kstatus, RDC_EENABLED, rdc_set->primary.intf, 2020 rdc_set->primary.file, rdc_set->secondary.intf, 2021 rdc_set->secondary.file); 2022 return (RDC_EENABLED); 2023 } 2024 2025 if (rdc_lookup_many2one(rdc_set) >= 0) { 2026 mutex_exit(&rdc_conf_lock); 2027 spcs_s_add(kstatus, RDC_EMANY2ONE, rdc_set->primary.intf, 2028 rdc_set->primary.file, rdc_set->secondary.intf, 2029 rdc_set->secondary.file); 2030 return (RDC_EMANY2ONE); 2031 } 2032 2033 if (rdc_set->netconfig->knc_proto == NULL) { 2034 mutex_exit(&rdc_conf_lock); 2035 spcs_s_add(kstatus, RDC_ENETCONFIG); 2036 return (RDC_ENETCONFIG); 2037 } 2038 2039 if (rdc_set->primary.addr.len == 0) { 2040 mutex_exit(&rdc_conf_lock); 2041 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->primary.file); 2042 return (RDC_ENETBUF); 2043 } 2044 2045 if (rdc_set->secondary.addr.len == 0) { 2046 mutex_exit(&rdc_conf_lock); 2047 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->secondary.file); 2048 return (RDC_ENETBUF); 2049 } 2050 2051 /* Check that the local data volume isn't in use as a bitmap */ 2052 if (options & RDC_OPT_PRIMARY) 2053 local_file = rdc_set->primary.file; 2054 else 2055 local_file = rdc_set->secondary.file; 2056 if (rdc_lookup_bitmap(local_file) >= 0) { 2057 mutex_exit(&rdc_conf_lock); 2058 spcs_s_add(kstatus, RDC_EVOLINUSE, local_file); 2059 return (RDC_EVOLINUSE); 2060 } 2061 2062 /* check that the secondary data volume isn't in use */ 2063 if (!(options & RDC_OPT_PRIMARY)) { 2064 local_file = rdc_set->secondary.file; 2065 if (rdc_lookup_secondary(local_file) >= 0) { 2066 mutex_exit(&rdc_conf_lock); 2067 spcs_s_add(kstatus, RDC_EVOLINUSE, local_file); 2068 return (RDC_EVOLINUSE); 2069 } 2070 } 2071 2072 /* check that the local data vol is not in use as a diskqueue */ 2073 if (options & RDC_OPT_PRIMARY) { 2074 if (rdc_lookup_diskq(rdc_set->primary.file) >= 0) { 2075 mutex_exit(&rdc_conf_lock); 2076 spcs_s_add(kstatus, 2077 RDC_EVOLINUSE, rdc_set->primary.file); 2078 return (RDC_EVOLINUSE); 2079 } 2080 } 2081 2082 /* Check that the bitmap isn't in use as a data volume */ 2083 if (options & RDC_OPT_PRIMARY) 2084 local_bitmap = rdc_set->primary.bitmap; 2085 else 2086 local_bitmap = rdc_set->secondary.bitmap; 2087 if (rdc_lookup_configured(local_bitmap) >= 0) { 2088 mutex_exit(&rdc_conf_lock); 2089 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap); 2090 return (RDC_EBMPINUSE); 2091 } 2092 2093 /* Check that the bitmap isn't already in use as a bitmap */ 2094 if (rdc_lookup_bitmap(local_bitmap) >= 0) { 2095 mutex_exit(&rdc_conf_lock); 2096 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap); 2097 return (RDC_EBMPINUSE); 2098 } 2099 2100 /* check that the diskq (if here) is not in use */ 2101 diskq = rdc_set->disk_queue; 2102 if (diskq[0] && rdc_diskq_inuse(rdc_set, diskq)) { 2103 mutex_exit(&rdc_conf_lock); 2104 spcs_s_add(kstatus, RDC_EDISKQINUSE, diskq); 2105 return (RDC_EDISKQINUSE); 2106 } 2107 2108 2109 /* Set urdc->volume_size */ 2110 index = rdc_dev_open(rdc_set, options); 2111 if (index < 0) { 2112 mutex_exit(&rdc_conf_lock); 2113 if (options & RDC_OPT_PRIMARY) 2114 spcs_s_add(kstatus, RDC_EOPEN, rdc_set->primary.intf, 2115 rdc_set->primary.file); 2116 else 2117 spcs_s_add(kstatus, RDC_EOPEN, rdc_set->secondary.intf, 2118 rdc_set->secondary.file); 2119 return (RDC_EOPEN); 2120 } 2121 2122 urdc = &rdc_u_info[index]; 2123 krdc = &rdc_k_info[index]; 2124 2125 /* copy relevant parts of rdc_set to urdc field by field */ 2126 2127 (void) strncpy(urdc->primary.intf, rdc_set->primary.intf, 2128 MAX_RDC_HOST_SIZE); 2129 (void) strncpy(urdc->secondary.intf, rdc_set->secondary.intf, 2130 MAX_RDC_HOST_SIZE); 2131 2132 (void) strncpy(urdc->group_name, rdc_set->group_name, NSC_MAXPATH); 2133 (void) strncpy(urdc->disk_queue, rdc_set->disk_queue, NSC_MAXPATH); 2134 2135 dup_rdc_netbuf(&rdc_set->primary.addr, &urdc->primary.addr); 2136 (void) strncpy(urdc->primary.file, rdc_set->primary.file, NSC_MAXPATH); 2137 (void) strncpy(urdc->primary.bitmap, rdc_set->primary.bitmap, 2138 NSC_MAXPATH); 2139 2140 dup_rdc_netbuf(&rdc_set->secondary.addr, &urdc->secondary.addr); 2141 (void) strncpy(urdc->secondary.file, rdc_set->secondary.file, 2142 NSC_MAXPATH); 2143 (void) strncpy(urdc->secondary.bitmap, rdc_set->secondary.bitmap, 2144 NSC_MAXPATH); 2145 2146 urdc->setid = rdc_set->setid; 2147 2148 /* 2149 * before we try to add to group, or create one, check out 2150 * if we are doing the wrong thing with the diskq 2151 */ 2152 2153 if (urdc->disk_queue[0] && (options & RDC_OPT_SYNC)) { 2154 mutex_exit(&rdc_conf_lock); 2155 rdc_dev_close(krdc); 2156 spcs_s_add(kstatus, RDC_EQWRONGMODE); 2157 return (RDC_EQWRONGMODE); 2158 } 2159 2160 if ((rc = add_to_group(krdc, options, RDC_CMD_ENABLE)) != 0) { 2161 mutex_exit(&rdc_conf_lock); 2162 rdc_dev_close(krdc); 2163 if (rc == RDC_EQNOADD) { 2164 spcs_s_add(kstatus, RDC_EQNOADD, rdc_set->disk_queue); 2165 return (RDC_EQNOADD); 2166 } else { 2167 spcs_s_add(kstatus, RDC_EGROUP, 2168 rdc_set->primary.intf, rdc_set->primary.file, 2169 rdc_set->secondary.intf, rdc_set->secondary.file, 2170 rdc_set->group_name); 2171 return (RDC_EGROUP); 2172 } 2173 } 2174 2175 /* 2176 * maxfbas was set in rdc_dev_open as primary's maxfbas. 2177 * If diskq's maxfbas is smaller, then use diskq's. 2178 */ 2179 grp = krdc->group; 2180 if (grp && RDC_IS_DISKQ(grp) && (grp->diskqfd != 0)) { 2181 rc = _rdc_rsrv_diskq(grp); 2182 if (RDC_SUCCESS(rc)) { 2183 rc = nsc_maxfbas(grp->diskqfd, 0, &maxfbas); 2184 if (rc == 0) { 2185 #ifdef DEBUG 2186 if (krdc->maxfbas != maxfbas) 2187 cmn_err(CE_NOTE, 2188 "!_rdc_enable: diskq maxfbas = %" 2189 NSC_SZFMT ", primary maxfbas = %" 2190 NSC_SZFMT, maxfbas, krdc->maxfbas); 2191 #endif 2192 krdc->maxfbas = min(krdc->maxfbas, maxfbas); 2193 } else { 2194 cmn_err(CE_WARN, 2195 "!_rdc_enable: diskq maxfbas failed (%d)", 2196 rc); 2197 } 2198 _rdc_rlse_diskq(grp); 2199 } else { 2200 cmn_err(CE_WARN, 2201 "!_rdc_enable: diskq reserve failed (%d)", rc); 2202 } 2203 } 2204 2205 rdc_init_flags(urdc); 2206 (void) strncpy(urdc->direct_file, rdc_set->direct_file, NSC_MAXPATH); 2207 if ((options & RDC_OPT_PRIMARY) && rdc_set->direct_file[0]) { 2208 if (rdc_open_direct(krdc) == NULL) 2209 rdc_set_flags(urdc, RDC_FCAL_FAILED); 2210 } 2211 2212 krdc->many_next = krdc; 2213 2214 ASSERT(krdc->type_flag == 0); 2215 krdc->type_flag = RDC_CONFIGURED; 2216 2217 if (options & RDC_OPT_PRIMARY) 2218 rdc_set_flags(urdc, RDC_PRIMARY); 2219 2220 if (options & RDC_OPT_ASYNC) 2221 krdc->type_flag |= RDC_ASYNCMODE; 2222 2223 set_busy(krdc); 2224 urdc->syshostid = rdc_set->syshostid; 2225 2226 if (add_to_many(krdc) < 0) { 2227 mutex_exit(&rdc_conf_lock); 2228 2229 rdc_group_enter(krdc); 2230 2231 spcs_s_add(kstatus, RDC_EMULTI); 2232 rc = RDC_EMULTI; 2233 goto fail; 2234 } 2235 2236 /* Configured but not enabled */ 2237 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2238 2239 mutex_exit(&rdc_conf_lock); 2240 2241 rdc_group_enter(krdc); 2242 2243 /* Configured but not enabled */ 2244 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2245 2246 /* 2247 * The rdc set is configured but not yet enabled. Other operations must 2248 * ignore this set until it is enabled. 2249 */ 2250 2251 urdc->sync_pos = 0; 2252 2253 if (rdc_set->maxqfbas > 0) 2254 urdc->maxqfbas = rdc_set->maxqfbas; 2255 else 2256 urdc->maxqfbas = rdc_maxthres_queue; 2257 2258 if (rdc_set->maxqitems > 0) 2259 urdc->maxqitems = rdc_set->maxqitems; 2260 else 2261 urdc->maxqitems = rdc_max_qitems; 2262 2263 if (rdc_set->asyncthr > 0) 2264 urdc->asyncthr = rdc_set->asyncthr; 2265 else 2266 urdc->asyncthr = rdc_asyncthr; 2267 2268 if (urdc->autosync == -1) { 2269 /* Still unknown */ 2270 if (rdc_set->autosync > 0) 2271 urdc->autosync = 1; 2272 else 2273 urdc->autosync = 0; 2274 } 2275 2276 urdc->netconfig = rdc_set->netconfig; 2277 2278 if (options & RDC_OPT_PRIMARY) { 2279 rhost = rdc_set->secondary.intf; 2280 addrp = &rdc_set->secondary.addr; 2281 } else { 2282 rhost = rdc_set->primary.intf; 2283 addrp = &rdc_set->primary.addr; 2284 } 2285 2286 if (options & RDC_OPT_ASYNC) 2287 rdc_set_flags(urdc, RDC_ASYNC); 2288 2289 svp = rdc_create_svinfo(rhost, addrp, urdc->netconfig); 2290 if (svp == NULL) { 2291 spcs_s_add(kstatus, ENOMEM); 2292 rc = ENOMEM; 2293 goto fail; 2294 } 2295 urdc->netconfig = NULL; /* This will be no good soon */ 2296 2297 rdc_kstat_create(index); 2298 2299 /* Don't set krdc->intf here */ 2300 2301 if (rdc_enable_bitmap(krdc, options & RDC_OPT_SETBMP) < 0) 2302 goto bmpfail; 2303 2304 RDC_ZERO_BITREF(krdc); 2305 if (krdc->lsrv == NULL) 2306 krdc->lsrv = svp; 2307 else { 2308 #ifdef DEBUG 2309 cmn_err(CE_WARN, "!_rdc_enable: krdc->lsrv already set: %p", 2310 (void *) krdc->lsrv); 2311 #endif 2312 rdc_destroy_svinfo(svp); 2313 } 2314 svp = NULL; 2315 2316 /* Configured but not enabled */ 2317 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2318 2319 /* And finally */ 2320 2321 krdc->remote_index = -1; 2322 /* Should we set the whole group logging? */ 2323 rdc_set_flags(urdc, RDC_ENABLED | RDC_LOGGING); 2324 2325 rdc_group_exit(krdc); 2326 2327 if (rdc_intercept(krdc) != 0) { 2328 rdc_group_enter(krdc); 2329 rdc_clr_flags(urdc, RDC_ENABLED); 2330 if (options & RDC_OPT_PRIMARY) 2331 spcs_s_add(kstatus, RDC_EREGISTER, urdc->primary.file); 2332 else 2333 spcs_s_add(kstatus, RDC_EREGISTER, 2334 urdc->secondary.file); 2335 #ifdef DEBUG 2336 cmn_err(CE_NOTE, "!nsc_register_path failed %s", 2337 urdc->primary.file); 2338 #endif 2339 rc = RDC_EREGISTER; 2340 goto bmpfail; 2341 } 2342 #ifdef DEBUG 2343 cmn_err(CE_NOTE, "!SNDR: enabled %s %s", urdc->primary.file, 2344 urdc->secondary.file); 2345 #endif 2346 2347 rdc_write_state(urdc); 2348 2349 mutex_enter(&rdc_conf_lock); 2350 wakeup_busy(krdc); 2351 mutex_exit(&rdc_conf_lock); 2352 2353 return (0); 2354 2355 bmpfail: 2356 if (options & RDC_OPT_PRIMARY) 2357 spcs_s_add(kstatus, RDC_EBITMAP, rdc_set->primary.bitmap); 2358 else 2359 spcs_s_add(kstatus, RDC_EBITMAP, rdc_set->secondary.bitmap); 2360 rc = RDC_EBITMAP; 2361 if (rdc_get_vflags(urdc) & RDC_ENABLED) { 2362 rdc_group_exit(krdc); 2363 (void) rdc_unintercept(krdc); 2364 rdc_group_enter(krdc); 2365 } 2366 2367 fail: 2368 rdc_kstat_delete(index); 2369 rdc_group_exit(krdc); 2370 if (krdc->intf) { 2371 rdc_if_t *ip = krdc->intf; 2372 mutex_enter(&rdc_conf_lock); 2373 krdc->intf = NULL; 2374 rdc_remove_from_if(ip); 2375 mutex_exit(&rdc_conf_lock); 2376 } 2377 rdc_group_enter(krdc); 2378 /* Configured but not enabled */ 2379 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2380 2381 rdc_dev_close(krdc); 2382 rdc_close_direct(krdc); 2383 rdc_destroy_svinfo(svp); 2384 2385 /* Configured but not enabled */ 2386 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2387 2388 rdc_group_exit(krdc); 2389 2390 mutex_enter(&rdc_conf_lock); 2391 2392 /* Configured but not enabled */ 2393 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2394 2395 remove_from_group(krdc); 2396 2397 if (IS_MANY(krdc) || IS_MULTI(krdc)) 2398 remove_from_many(krdc); 2399 2400 rdc_u_init(urdc); 2401 2402 ASSERT(krdc->type_flag & RDC_CONFIGURED); 2403 krdc->type_flag = 0; 2404 wakeup_busy(krdc); 2405 2406 mutex_exit(&rdc_conf_lock); 2407 2408 return (rc); 2409 } 2410 2411 static int 2412 rdc_enable(rdc_config_t *uparms, spcs_s_info_t kstatus) 2413 { 2414 int rc; 2415 char itmp[10]; 2416 2417 if (!(uparms->options & RDC_OPT_SYNC) && 2418 !(uparms->options & RDC_OPT_ASYNC)) { 2419 rc = RDC_EEINVAL; 2420 (void) spcs_s_inttostring( 2421 uparms->options, itmp, sizeof (itmp), 1); 2422 spcs_s_add(kstatus, RDC_EEINVAL, itmp); 2423 goto done; 2424 } 2425 2426 if (!(uparms->options & RDC_OPT_PRIMARY) && 2427 !(uparms->options & RDC_OPT_SECONDARY)) { 2428 rc = RDC_EEINVAL; 2429 (void) spcs_s_inttostring( 2430 uparms->options, itmp, sizeof (itmp), 1); 2431 spcs_s_add(kstatus, RDC_EEINVAL, itmp); 2432 goto done; 2433 } 2434 2435 if (!(uparms->options & RDC_OPT_SETBMP) && 2436 !(uparms->options & RDC_OPT_CLRBMP)) { 2437 rc = RDC_EEINVAL; 2438 (void) spcs_s_inttostring( 2439 uparms->options, itmp, sizeof (itmp), 1); 2440 spcs_s_add(kstatus, RDC_EEINVAL, itmp); 2441 goto done; 2442 } 2443 2444 rc = _rdc_enable(uparms->rdc_set, uparms->options, kstatus); 2445 done: 2446 return (rc); 2447 } 2448 2449 /* ARGSUSED */ 2450 static int 2451 _rdc_disable(rdc_k_info_t *krdc, rdc_config_t *uap, spcs_s_info_t kstatus) 2452 { 2453 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 2454 rdc_if_t *ip; 2455 int index = krdc->index; 2456 disk_queue *q; 2457 rdc_set_t *rdc_set = uap->rdc_set; 2458 2459 ASSERT(krdc->group != NULL); 2460 rdc_group_enter(krdc); 2461 #ifdef DEBUG 2462 ASSERT(rdc_check(krdc, rdc_set) == 0); 2463 #else 2464 if (((uap->options & RDC_OPT_FORCE_DISABLE) == 0) && 2465 rdc_check(krdc, rdc_set)) { 2466 rdc_group_exit(krdc); 2467 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file, 2468 rdc_set->secondary.file); 2469 return (RDC_EALREADY); 2470 } 2471 #endif 2472 2473 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 2474 halt_sync(krdc); 2475 ASSERT(IS_ENABLED(urdc)); 2476 } 2477 q = &krdc->group->diskq; 2478 2479 if (IS_ASYNC(urdc) && RDC_IS_DISKQ(krdc->group) && 2480 ((!IS_STATE(urdc, RDC_LOGGING)) && (!QEMPTY(q)))) { 2481 krdc->type_flag &= ~RDC_DISABLEPEND; 2482 rdc_group_exit(krdc); 2483 spcs_s_add(kstatus, RDC_EQNOTEMPTY, urdc->disk_queue); 2484 return (RDC_EQNOTEMPTY); 2485 } 2486 rdc_group_exit(krdc); 2487 (void) rdc_unintercept(krdc); 2488 2489 #ifdef DEBUG 2490 cmn_err(CE_NOTE, "!SNDR: disabled %s %s", urdc->primary.file, 2491 urdc->secondary.file); 2492 #endif 2493 2494 /* Configured but not enabled */ 2495 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2496 2497 /* 2498 * No new io can come in through the io provider. 2499 * Wait for the async flusher to finish. 2500 */ 2501 2502 if (IS_ASYNC(urdc) && !RDC_IS_DISKQ(krdc->group)) { 2503 int tries = 2; /* in case of hopelessly stuck flusher threads */ 2504 #ifdef DEBUG 2505 net_queue *qp = &krdc->group->ra_queue; 2506 #endif 2507 do { 2508 if (!krdc->group->rdc_writer) 2509 (void) rdc_writer(krdc->index); 2510 2511 (void) rdc_drain_queue(krdc->index); 2512 2513 } while (krdc->group->rdc_writer && tries--); 2514 2515 /* ok, force it to happen... */ 2516 if (rdc_drain_queue(krdc->index) != 0) { 2517 do { 2518 mutex_enter(&krdc->group->ra_queue.net_qlock); 2519 krdc->group->asyncdis = 1; 2520 cv_broadcast(&krdc->group->asyncqcv); 2521 mutex_exit(&krdc->group->ra_queue.net_qlock); 2522 cmn_err(CE_WARN, 2523 "!SNDR: async I/O pending and not flushed " 2524 "for %s during disable", 2525 urdc->primary.file); 2526 #ifdef DEBUG 2527 cmn_err(CE_WARN, 2528 "!nitems: %" NSC_SZFMT " nblocks: %" 2529 NSC_SZFMT " head: 0x%p tail: 0x%p", 2530 qp->nitems, qp->blocks, 2531 (void *)qp->net_qhead, 2532 (void *)qp->net_qtail); 2533 #endif 2534 } while (krdc->group->rdc_thrnum > 0); 2535 } 2536 } 2537 2538 mutex_enter(&rdc_conf_lock); 2539 ip = krdc->intf; 2540 krdc->intf = 0; 2541 2542 if (ip) { 2543 rdc_remove_from_if(ip); 2544 } 2545 2546 mutex_exit(&rdc_conf_lock); 2547 2548 rdc_group_enter(krdc); 2549 2550 /* Configured but not enabled */ 2551 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2552 2553 /* Must not hold group lock during this function */ 2554 rdc_group_exit(krdc); 2555 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN) 2556 delay(2); 2557 rdc_group_enter(krdc); 2558 2559 (void) rdc_clear_state(krdc); 2560 2561 rdc_free_bitmap(krdc, RDC_CMD_DISABLE); 2562 rdc_close_bitmap(krdc); 2563 2564 rdc_dev_close(krdc); 2565 rdc_close_direct(krdc); 2566 2567 /* Configured but not enabled */ 2568 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2569 2570 rdc_group_exit(krdc); 2571 2572 /* 2573 * we should now unregister the queue, with no conflicting 2574 * locks held. This is the last(only) member of the group 2575 */ 2576 if (krdc->group && RDC_IS_DISKQ(krdc->group) && 2577 krdc->group->count == 1) { /* stop protecting queue */ 2578 rdc_unintercept_diskq(krdc->group); 2579 } 2580 2581 mutex_enter(&rdc_conf_lock); 2582 2583 /* Configured but not enabled */ 2584 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 2585 2586 wait_busy(krdc); 2587 2588 if (IS_MANY(krdc) || IS_MULTI(krdc)) 2589 remove_from_many(krdc); 2590 2591 remove_from_group(krdc); 2592 2593 krdc->remote_index = -1; 2594 ASSERT(krdc->type_flag & RDC_CONFIGURED); 2595 ASSERT(krdc->type_flag & RDC_DISABLEPEND); 2596 krdc->type_flag = 0; 2597 #ifdef DEBUG 2598 if (krdc->dcio_bitmap) 2599 cmn_err(CE_WARN, "!_rdc_disable: possible mem leak, " 2600 "dcio_bitmap"); 2601 #endif 2602 krdc->dcio_bitmap = NULL; 2603 krdc->bitmap_ref = NULL; 2604 krdc->bitmap_size = 0; 2605 krdc->maxfbas = 0; 2606 krdc->bitmap_write = 0; 2607 krdc->disk_status = 0; 2608 rdc_destroy_svinfo(krdc->lsrv); 2609 krdc->lsrv = NULL; 2610 krdc->multi_next = NULL; 2611 2612 rdc_u_init(urdc); 2613 2614 mutex_exit(&rdc_conf_lock); 2615 rdc_kstat_delete(index); 2616 2617 return (0); 2618 } 2619 2620 static int 2621 rdc_disable(rdc_config_t *uparms, spcs_s_info_t kstatus) 2622 { 2623 rdc_k_info_t *krdc; 2624 int index; 2625 int rc; 2626 2627 mutex_enter(&rdc_conf_lock); 2628 2629 index = rdc_lookup_byname(uparms->rdc_set); 2630 if (index >= 0) 2631 krdc = &rdc_k_info[index]; 2632 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 2633 mutex_exit(&rdc_conf_lock); 2634 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 2635 uparms->rdc_set->secondary.file); 2636 return (RDC_EALREADY); 2637 } 2638 2639 krdc->type_flag |= RDC_DISABLEPEND; 2640 wait_busy(krdc); 2641 if (krdc->type_flag == 0) { 2642 /* A resume or enable failed */ 2643 mutex_exit(&rdc_conf_lock); 2644 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 2645 uparms->rdc_set->secondary.file); 2646 return (RDC_EALREADY); 2647 } 2648 mutex_exit(&rdc_conf_lock); 2649 2650 rc = _rdc_disable(krdc, uparms, kstatus); 2651 return (rc); 2652 } 2653 2654 2655 /* 2656 * Checks whether the state of one of the other sets in the 1-many or 2657 * multi-hop config should prevent a sync from starting on this one. 2658 * Return NULL if no just cause or impediment is found, otherwise return 2659 * a pointer to the offending set. 2660 */ 2661 static rdc_u_info_t * 2662 rdc_allow_pri_sync(rdc_u_info_t *urdc, int options) 2663 { 2664 rdc_k_info_t *krdc = &rdc_k_info[urdc->index]; 2665 rdc_k_info_t *ktmp; 2666 rdc_u_info_t *utmp; 2667 rdc_k_info_t *kmulti = NULL; 2668 2669 ASSERT(rdc_get_vflags(urdc) & RDC_PRIMARY); 2670 2671 rdc_many_enter(krdc); 2672 2673 /* 2674 * In the reverse sync case we need to check the previous leg of 2675 * the multi-hop config. The link to that set can be from any of 2676 * the 1-many list, so as we go through we keep an eye open for it. 2677 */ 2678 if ((options & RDC_OPT_REVERSE) && (IS_MULTI(krdc))) { 2679 /* This set links to the first leg */ 2680 ktmp = krdc->multi_next; 2681 utmp = &rdc_u_info[ktmp->index]; 2682 if (IS_ENABLED(utmp)) 2683 kmulti = ktmp; 2684 } 2685 2686 if (IS_MANY(krdc)) { 2687 for (ktmp = krdc->many_next; ktmp != krdc; 2688 ktmp = ktmp->many_next) { 2689 utmp = &rdc_u_info[ktmp->index]; 2690 2691 if (!IS_ENABLED(utmp)) 2692 continue; 2693 2694 if (options & RDC_OPT_FORWARD) { 2695 /* 2696 * Reverse sync needed is bad, as it means a 2697 * reverse sync in progress or started and 2698 * didn't complete, so this primary volume 2699 * is not consistent. So we shouldn't copy 2700 * it to its secondary. 2701 */ 2702 if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED) { 2703 rdc_many_exit(krdc); 2704 return (utmp); 2705 } 2706 } else { 2707 /* Reverse, so see if we need to spot kmulti */ 2708 if ((kmulti == NULL) && (IS_MULTI(ktmp))) { 2709 /* This set links to the first leg */ 2710 kmulti = ktmp->multi_next; 2711 if (!IS_ENABLED( 2712 &rdc_u_info[kmulti->index])) 2713 kmulti = NULL; 2714 } 2715 2716 /* 2717 * Non-logging is bad, as the bitmap will 2718 * be updated with the bits for this sync. 2719 */ 2720 if (!(rdc_get_vflags(utmp) & RDC_LOGGING)) { 2721 rdc_many_exit(krdc); 2722 return (utmp); 2723 } 2724 } 2725 } 2726 } 2727 2728 if (kmulti) { 2729 utmp = &rdc_u_info[kmulti->index]; 2730 ktmp = kmulti; /* In case we decide we do need to use ktmp */ 2731 2732 ASSERT(options & RDC_OPT_REVERSE); 2733 2734 if (IS_REPLICATING(utmp)) { 2735 /* 2736 * Replicating is bad as data is already flowing to 2737 * the target of the requested sync operation. 2738 */ 2739 rdc_many_exit(krdc); 2740 return (utmp); 2741 } 2742 2743 if (rdc_get_vflags(utmp) & RDC_SYNCING) { 2744 /* 2745 * Forward sync in progress is bad, as data is 2746 * already flowing to the target of the requested 2747 * sync operation. 2748 * Reverse sync in progress is bad, as the primary 2749 * has already decided which data to copy. 2750 */ 2751 rdc_many_exit(krdc); 2752 return (utmp); 2753 } 2754 2755 /* 2756 * Clear the "sync needed" flags, as the multi-hop secondary 2757 * will be updated via this requested sync operation, so does 2758 * not need to complete its aborted forward sync. 2759 */ 2760 if (rdc_get_vflags(utmp) & RDC_SYNC_NEEDED) 2761 rdc_clr_flags(utmp, RDC_SYNC_NEEDED); 2762 } 2763 2764 if (IS_MANY(krdc) && (options & RDC_OPT_REVERSE)) { 2765 for (ktmp = krdc->many_next; ktmp != krdc; 2766 ktmp = ktmp->many_next) { 2767 utmp = &rdc_u_info[ktmp->index]; 2768 if (!IS_ENABLED(utmp)) 2769 continue; 2770 2771 /* 2772 * Clear any "reverse sync needed" flags, as the 2773 * volume will be updated via this requested 2774 * sync operation, so does not need to complete 2775 * its aborted reverse sync. 2776 */ 2777 if (rdc_get_mflags(utmp) & RDC_RSYNC_NEEDED) 2778 rdc_clr_mflags(utmp, RDC_RSYNC_NEEDED); 2779 } 2780 } 2781 2782 rdc_many_exit(krdc); 2783 2784 return (NULL); 2785 } 2786 2787 static void 2788 _rdc_sync_wrthr(void *thrinfo) 2789 { 2790 rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo; 2791 nsc_buf_t *handle = NULL; 2792 rdc_k_info_t *krdc = syncinfo->krdc; 2793 int rc; 2794 int tries = 0; 2795 2796 DTRACE_PROBE2(rdc_sync_loop_netwrite_start, int, krdc->index, 2797 nsc_buf_t *, handle); 2798 2799 retry: 2800 rc = nsc_alloc_buf(RDC_U_FD(krdc), syncinfo->offset, syncinfo->len, 2801 NSC_READ | NSC_NOCACHE, &handle); 2802 2803 if (!RDC_SUCCESS(rc) || krdc->remote_index < 0) { 2804 DTRACE_PROBE(rdc_sync_wrthr_alloc_buf_err); 2805 goto failed; 2806 } 2807 2808 rdc_group_enter(krdc); 2809 if ((krdc->disk_status == 1) || (krdc->dcio_bitmap == NULL)) { 2810 rdc_group_exit(krdc); 2811 goto failed; 2812 } 2813 rdc_group_exit(krdc); 2814 2815 if ((rc = rdc_net_write(krdc->index, krdc->remote_index, handle, 2816 handle->sb_pos, handle->sb_len, RDC_NOSEQ, RDC_NOQUE, NULL)) > 0) { 2817 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 2818 2819 /* 2820 * The following is to handle 2821 * the case where the secondary side 2822 * has thrown our buffer handle token away in a 2823 * attempt to preserve its health on restart 2824 */ 2825 if ((rc == EPROTO) && (tries < 3)) { 2826 (void) nsc_free_buf(handle); 2827 handle = NULL; 2828 tries++; 2829 delay(HZ >> 2); 2830 goto retry; 2831 } 2832 2833 DTRACE_PROBE(rdc_sync_wrthr_remote_write_err); 2834 cmn_err(CE_WARN, "!rdc_sync_wrthr: remote write failed (%d) " 2835 "0x%x", rc, rdc_get_vflags(urdc)); 2836 2837 goto failed; 2838 } 2839 (void) nsc_free_buf(handle); 2840 handle = NULL; 2841 2842 return; 2843 failed: 2844 (void) nsc_free_buf(handle); 2845 syncinfo->status->offset = syncinfo->offset; 2846 } 2847 2848 /* 2849 * see above comments on _rdc_sync_wrthr 2850 */ 2851 static void 2852 _rdc_sync_rdthr(void *thrinfo) 2853 { 2854 rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo; 2855 nsc_buf_t *handle = NULL; 2856 rdc_k_info_t *krdc = syncinfo->krdc; 2857 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 2858 int rc; 2859 2860 rc = nsc_alloc_buf(RDC_U_FD(krdc), syncinfo->offset, syncinfo->len, 2861 NSC_WRITE | NSC_WRTHRU | NSC_NOCACHE, &handle); 2862 2863 if (!RDC_SUCCESS(rc) || krdc->remote_index < 0) { 2864 goto failed; 2865 } 2866 rdc_group_enter(krdc); 2867 if ((krdc->disk_status == 1) || (krdc->dcio_bitmap == NULL)) { 2868 rdc_group_exit(krdc); 2869 goto failed; 2870 } 2871 rdc_group_exit(krdc); 2872 2873 rc = rdc_net_read(krdc->index, krdc->remote_index, handle, 2874 handle->sb_pos, handle->sb_len); 2875 2876 if (!RDC_SUCCESS(rc)) { 2877 cmn_err(CE_WARN, "!rdc_sync_rdthr: remote read failed(%d)", rc); 2878 goto failed; 2879 } 2880 if (!IS_STATE(urdc, RDC_FULL)) 2881 rdc_set_bitmap_many(krdc, handle->sb_pos, handle->sb_len); 2882 2883 rc = nsc_write(handle, handle->sb_pos, handle->sb_len, 0); 2884 2885 if (!RDC_SUCCESS(rc)) { 2886 rdc_many_enter(krdc); 2887 rdc_set_flags_log(urdc, RDC_VOL_FAILED, "nsc_write failed"); 2888 rdc_many_exit(krdc); 2889 rdc_write_state(urdc); 2890 goto failed; 2891 } 2892 2893 (void) nsc_free_buf(handle); 2894 handle = NULL; 2895 2896 return; 2897 failed: 2898 (void) nsc_free_buf(handle); 2899 syncinfo->status->offset = syncinfo->offset; 2900 } 2901 2902 /* 2903 * _rdc_sync_wrthr 2904 * sync loop write thread 2905 * if there are avail threads, we have not 2906 * used up the pipe, so the sync loop will, if 2907 * possible use these to multithread the write/read 2908 */ 2909 void 2910 _rdc_sync_thread(void *thrinfo) 2911 { 2912 rdc_syncthr_t *syncinfo = (rdc_syncthr_t *)thrinfo; 2913 rdc_k_info_t *krdc = syncinfo->krdc; 2914 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 2915 rdc_thrsync_t *sync = &krdc->syncs; 2916 uint_t bitmask; 2917 int rc; 2918 2919 rc = _rdc_rsrv_devs(krdc, RDC_RAW, RDC_INTERNAL); 2920 if (!RDC_SUCCESS(rc)) 2921 goto failed; 2922 2923 if (IS_STATE(urdc, RDC_SLAVE)) 2924 _rdc_sync_rdthr(thrinfo); 2925 else 2926 _rdc_sync_wrthr(thrinfo); 2927 2928 _rdc_rlse_devs(krdc, RDC_RAW); 2929 2930 if (krdc->dcio_bitmap == NULL) { 2931 #ifdef DEBUG 2932 cmn_err(CE_NOTE, "!_rdc_sync_wrthr: NULL bitmap"); 2933 #else 2934 /*EMPTY*/ 2935 #endif 2936 } else if (syncinfo->status->offset < 0) { 2937 2938 RDC_SET_BITMASK(syncinfo->offset, syncinfo->len, &bitmask); 2939 RDC_CLR_BITMAP(krdc, syncinfo->offset, syncinfo->len, \ 2940 bitmask, RDC_BIT_FORCE); 2941 } 2942 2943 failed: 2944 /* 2945 * done with this, get rid of it. 2946 * the status is not freed, it should still be a status chain 2947 * that _rdc_sync() has the head of 2948 */ 2949 kmem_free(syncinfo, sizeof (*syncinfo)); 2950 2951 /* 2952 * decrement the global sync thread num 2953 */ 2954 mutex_enter(&sync_info.lock); 2955 sync_info.active_thr--; 2956 /* LINTED */ 2957 RDC_AVAIL_THR_TUNE(sync_info); 2958 mutex_exit(&sync_info.lock); 2959 2960 /* 2961 * krdc specific stuff 2962 */ 2963 mutex_enter(&sync->lock); 2964 sync->complete++; 2965 cv_broadcast(&sync->cv); 2966 mutex_exit(&sync->lock); 2967 } 2968 2969 int 2970 _rdc_setup_syncthr(rdc_syncthr_t **synthr, nsc_off_t offset, 2971 nsc_size_t len, rdc_k_info_t *krdc, sync_status_t *stats) 2972 { 2973 rdc_syncthr_t *tmp; 2974 /* alloc here, free in the sync thread */ 2975 tmp = 2976 (rdc_syncthr_t *)kmem_zalloc(sizeof (rdc_syncthr_t), KM_NOSLEEP); 2977 2978 if (tmp == NULL) 2979 return (-1); 2980 tmp->offset = offset; 2981 tmp->len = len; 2982 tmp->status = stats; 2983 tmp->krdc = krdc; 2984 2985 *synthr = tmp; 2986 return (0); 2987 } 2988 2989 sync_status_t * 2990 _rdc_new_sync_status() 2991 { 2992 sync_status_t *s; 2993 2994 s = (sync_status_t *)kmem_zalloc(sizeof (*s), KM_NOSLEEP); 2995 s->offset = -1; 2996 return (s); 2997 } 2998 2999 void 3000 _rdc_free_sync_status(sync_status_t *status) 3001 { 3002 sync_status_t *s; 3003 3004 while (status) { 3005 s = status->next; 3006 kmem_free(status, sizeof (*status)); 3007 status = s; 3008 } 3009 } 3010 int 3011 _rdc_sync_status_ok(sync_status_t *status, int *offset) 3012 { 3013 #ifdef DEBUG_SYNCSTATUS 3014 int i = 0; 3015 #endif 3016 while (status) { 3017 if (status->offset >= 0) { 3018 *offset = status->offset; 3019 return (-1); 3020 } 3021 status = status->next; 3022 #ifdef DEBUG_SYNCSTATUS 3023 i++; 3024 #endif 3025 } 3026 #ifdef DEBUGSYNCSTATUS 3027 cmn_err(CE_NOTE, "!rdc_sync_status_ok: checked %d statuses", i); 3028 #endif 3029 return (0); 3030 } 3031 3032 int mtsync = 1; 3033 /* 3034 * _rdc_sync() : rdc sync loop 3035 * 3036 */ 3037 static void 3038 _rdc_sync(rdc_k_info_t *krdc) 3039 { 3040 nsc_size_t size = 0; 3041 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 3042 int rtype; 3043 int sts; 3044 int reserved = 0; 3045 nsc_buf_t *alloc_h = NULL; 3046 nsc_buf_t *handle = NULL; 3047 nsc_off_t mask; 3048 nsc_size_t maxbit; 3049 nsc_size_t len; 3050 nsc_off_t offset = 0; 3051 int sync_completed = 0; 3052 int tries = 0; 3053 int rc; 3054 int queuing = 0; 3055 uint_t bitmask; 3056 sync_status_t *ss, *sync_status = NULL; 3057 rdc_thrsync_t *sync = &krdc->syncs; 3058 rdc_syncthr_t *syncinfo; 3059 nsthread_t *trc = NULL; 3060 3061 if (IS_STATE(urdc, RDC_QUEUING) && !IS_STATE(urdc, RDC_FULL)) { 3062 /* flusher is handling the sync in the update case */ 3063 queuing = 1; 3064 goto sync_done; 3065 } 3066 3067 /* 3068 * Main sync/resync loop 3069 */ 3070 DTRACE_PROBE(rdc_sync_loop_start); 3071 3072 rtype = RDC_RAW; 3073 sts = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL); 3074 3075 DTRACE_PROBE(rdc_sync_loop_rsrv); 3076 3077 if (sts != 0) 3078 goto failed_noincr; 3079 3080 reserved = 1; 3081 3082 /* 3083 * pre-allocate a handle if we can - speeds up the sync. 3084 */ 3085 3086 if (rdc_prealloc_handle) { 3087 alloc_h = nsc_alloc_handle(RDC_U_FD(krdc), NULL, NULL, NULL); 3088 #ifdef DEBUG 3089 if (!alloc_h) { 3090 cmn_err(CE_WARN, 3091 "!rdc sync: failed to pre-alloc handle"); 3092 } 3093 #endif 3094 } else { 3095 alloc_h = NULL; 3096 } 3097 3098 ASSERT(urdc->volume_size != 0); 3099 size = urdc->volume_size; 3100 mask = ~(LOG_TO_FBA_NUM(1) - 1); 3101 maxbit = FBA_TO_LOG_NUM(size - 1); 3102 3103 /* 3104 * as this while loop can also move data, it is counted as a 3105 * sync loop thread 3106 */ 3107 rdc_group_enter(krdc); 3108 rdc_clr_flags(urdc, RDC_LOGGING); 3109 rdc_set_flags(urdc, RDC_SYNCING); 3110 krdc->group->synccount++; 3111 rdc_group_exit(krdc); 3112 mutex_enter(&sync_info.lock); 3113 sync_info.active_thr++; 3114 /* LINTED */ 3115 RDC_AVAIL_THR_TUNE(sync_info); 3116 mutex_exit(&sync_info.lock); 3117 3118 while (offset < size) { 3119 rdc_group_enter(krdc); 3120 ASSERT(krdc->aux_state & RDC_AUXSYNCIP); 3121 if (krdc->disk_status == 1 || krdc->dcio_bitmap == NULL) { 3122 rdc_group_exit(krdc); 3123 if (krdc->disk_status == 1) { 3124 DTRACE_PROBE(rdc_sync_loop_disk_status_err); 3125 } else { 3126 DTRACE_PROBE(rdc_sync_loop_dcio_bitmap_err); 3127 } 3128 goto failed; /* halt sync */ 3129 } 3130 rdc_group_exit(krdc); 3131 3132 if (!(rdc_get_vflags(urdc) & RDC_FULL)) { 3133 mutex_enter(&krdc->syncbitmutex); 3134 krdc->syncbitpos = FBA_TO_LOG_NUM(offset); 3135 len = 0; 3136 3137 /* skip unnecessary chunks */ 3138 3139 while (krdc->syncbitpos <= maxbit && 3140 !RDC_BIT_ISSET(krdc, krdc->syncbitpos)) { 3141 offset += LOG_TO_FBA_NUM(1); 3142 krdc->syncbitpos++; 3143 } 3144 3145 /* check for boundary */ 3146 3147 if (offset >= size) { 3148 mutex_exit(&krdc->syncbitmutex); 3149 goto sync_done; 3150 } 3151 3152 /* find maximal length we can transfer */ 3153 3154 while (krdc->syncbitpos <= maxbit && 3155 RDC_BIT_ISSET(krdc, krdc->syncbitpos)) { 3156 len += LOG_TO_FBA_NUM(1); 3157 krdc->syncbitpos++; 3158 /* we can only read maxfbas anyways */ 3159 if (len >= krdc->maxfbas) 3160 break; 3161 } 3162 3163 len = min(len, (size - offset)); 3164 3165 } else { 3166 len = size - offset; 3167 } 3168 3169 /* truncate to the io provider limit */ 3170 ASSERT(krdc->maxfbas != 0); 3171 len = min(len, krdc->maxfbas); 3172 3173 if (len > LOG_TO_FBA_NUM(1)) { 3174 /* 3175 * If the update is larger than a bitmap chunk, 3176 * then truncate to a whole number of bitmap 3177 * chunks. 3178 * 3179 * If the update is smaller than a bitmap 3180 * chunk, this must be the last write. 3181 */ 3182 len &= mask; 3183 } 3184 3185 if (!(rdc_get_vflags(urdc) & RDC_FULL)) { 3186 krdc->syncbitpos = FBA_TO_LOG_NUM(offset + len); 3187 mutex_exit(&krdc->syncbitmutex); 3188 } 3189 3190 /* 3191 * Find out if we can reserve a thread here ... 3192 * note: skip the mutex for the first check, if the number 3193 * is up there, why bother even grabbing the mutex to 3194 * only realize that we can't have a thread anyways 3195 */ 3196 3197 if (mtsync && sync_info.active_thr < RDC_MAX_SYNC_THREADS) { 3198 3199 mutex_enter(&sync_info.lock); 3200 if (sync_info.avail_thr >= 1) { 3201 if (sync_status == NULL) { 3202 ss = sync_status = 3203 _rdc_new_sync_status(); 3204 } else { 3205 ss = ss->next = _rdc_new_sync_status(); 3206 } 3207 if (ss == NULL) { 3208 mutex_exit(&sync_info.lock); 3209 #ifdef DEBUG 3210 cmn_err(CE_WARN, "!rdc_sync: can't " 3211 "allocate status for mt sync"); 3212 #endif 3213 goto retry; 3214 } 3215 /* 3216 * syncinfo protected by sync_info lock but 3217 * not part of the sync_info structure 3218 * be careful if moving 3219 */ 3220 if (_rdc_setup_syncthr(&syncinfo, 3221 offset, len, krdc, ss) < 0) { 3222 _rdc_free_sync_status(ss); 3223 } 3224 3225 trc = nst_create(sync_info.rdc_syncset, 3226 _rdc_sync_thread, syncinfo, NST_SLEEP); 3227 3228 if (trc == NULL) { 3229 mutex_exit(&sync_info.lock); 3230 #ifdef DEBUG 3231 cmn_err(CE_NOTE, "!rdc_sync: unable to " 3232 "mt sync"); 3233 #endif 3234 _rdc_free_sync_status(ss); 3235 kmem_free(syncinfo, sizeof (*syncinfo)); 3236 syncinfo = NULL; 3237 goto retry; 3238 } else { 3239 mutex_enter(&sync->lock); 3240 sync->threads++; 3241 mutex_exit(&sync->lock); 3242 } 3243 3244 sync_info.active_thr++; 3245 /* LINTED */ 3246 RDC_AVAIL_THR_TUNE(sync_info); 3247 3248 mutex_exit(&sync_info.lock); 3249 goto threaded; 3250 } 3251 mutex_exit(&sync_info.lock); 3252 } 3253 retry: 3254 handle = alloc_h; 3255 DTRACE_PROBE(rdc_sync_loop_allocbuf_start); 3256 if (rdc_get_vflags(urdc) & RDC_SLAVE) 3257 sts = nsc_alloc_buf(RDC_U_FD(krdc), offset, len, 3258 NSC_WRITE | NSC_WRTHRU | NSC_NOCACHE, &handle); 3259 else 3260 sts = nsc_alloc_buf(RDC_U_FD(krdc), offset, len, 3261 NSC_READ | NSC_NOCACHE, &handle); 3262 3263 DTRACE_PROBE(rdc_sync_loop_allocbuf_end); 3264 if (sts > 0) { 3265 if (handle && handle != alloc_h) { 3266 (void) nsc_free_buf(handle); 3267 } 3268 3269 handle = NULL; 3270 DTRACE_PROBE(rdc_sync_loop_allocbuf_err); 3271 goto failed; 3272 } 3273 3274 if (rdc_get_vflags(urdc) & RDC_SLAVE) { 3275 /* overwrite buffer with remote data */ 3276 sts = rdc_net_read(krdc->index, krdc->remote_index, 3277 handle, handle->sb_pos, handle->sb_len); 3278 3279 if (!RDC_SUCCESS(sts)) { 3280 #ifdef DEBUG 3281 cmn_err(CE_WARN, 3282 "!rdc sync: remote read failed (%d)", sts); 3283 #endif 3284 DTRACE_PROBE(rdc_sync_loop_remote_read_err); 3285 goto failed; 3286 } 3287 if (!(rdc_get_vflags(urdc) & RDC_FULL)) 3288 rdc_set_bitmap_many(krdc, handle->sb_pos, 3289 handle->sb_len); 3290 3291 /* commit locally */ 3292 3293 sts = nsc_write(handle, handle->sb_pos, 3294 handle->sb_len, 0); 3295 3296 if (!RDC_SUCCESS(sts)) { 3297 /* reverse sync needed already set */ 3298 rdc_many_enter(krdc); 3299 rdc_set_flags_log(urdc, RDC_VOL_FAILED, 3300 "write failed during sync"); 3301 rdc_many_exit(krdc); 3302 rdc_write_state(urdc); 3303 DTRACE_PROBE(rdc_sync_loop_nsc_write_err); 3304 goto failed; 3305 } 3306 } else { 3307 /* send local data to remote */ 3308 DTRACE_PROBE2(rdc_sync_loop_netwrite_start, 3309 int, krdc->index, nsc_buf_t *, handle); 3310 3311 if ((sts = rdc_net_write(krdc->index, 3312 krdc->remote_index, handle, handle->sb_pos, 3313 handle->sb_len, RDC_NOSEQ, RDC_NOQUE, NULL)) > 0) { 3314 3315 /* 3316 * The following is to handle 3317 * the case where the secondary side 3318 * has thrown our buffer handle token away in a 3319 * attempt to preserve its health on restart 3320 */ 3321 if ((sts == EPROTO) && (tries < 3)) { 3322 (void) nsc_free_buf(handle); 3323 handle = NULL; 3324 tries++; 3325 delay(HZ >> 2); 3326 goto retry; 3327 } 3328 #ifdef DEBUG 3329 cmn_err(CE_WARN, 3330 "!rdc sync: remote write failed (%d) 0x%x", 3331 sts, rdc_get_vflags(urdc)); 3332 #endif 3333 DTRACE_PROBE(rdc_sync_loop_netwrite_err); 3334 goto failed; 3335 } 3336 DTRACE_PROBE(rdc_sync_loop_netwrite_end); 3337 } 3338 3339 (void) nsc_free_buf(handle); 3340 handle = NULL; 3341 3342 if (krdc->dcio_bitmap == NULL) { 3343 #ifdef DEBUG 3344 cmn_err(CE_NOTE, "!_rdc_sync: NULL bitmap"); 3345 #else 3346 ; 3347 /*EMPTY*/ 3348 #endif 3349 } else { 3350 3351 RDC_SET_BITMASK(offset, len, &bitmask); 3352 RDC_CLR_BITMAP(krdc, offset, len, bitmask, \ 3353 RDC_BIT_FORCE); 3354 ASSERT(!IS_ASYNC(urdc)); 3355 } 3356 3357 /* 3358 * Only release/reserve if someone is waiting 3359 */ 3360 if (krdc->devices->id_release || nsc_waiting(RDC_U_FD(krdc))) { 3361 DTRACE_PROBE(rdc_sync_loop_rlse_start); 3362 if (alloc_h) { 3363 (void) nsc_free_handle(alloc_h); 3364 alloc_h = NULL; 3365 } 3366 3367 _rdc_rlse_devs(krdc, rtype); 3368 reserved = 0; 3369 delay(2); 3370 3371 rtype = RDC_RAW; 3372 sts = _rdc_rsrv_devs(krdc, rtype, RDC_INTERNAL); 3373 if (sts != 0) { 3374 handle = NULL; 3375 DTRACE_PROBE(rdc_sync_loop_rdc_rsrv_err); 3376 goto failed; 3377 } 3378 3379 reserved = 1; 3380 3381 if (rdc_prealloc_handle) { 3382 alloc_h = nsc_alloc_handle(RDC_U_FD(krdc), 3383 NULL, NULL, NULL); 3384 #ifdef DEBUG 3385 if (!alloc_h) { 3386 cmn_err(CE_WARN, "!rdc_sync: " 3387 "failed to pre-alloc handle"); 3388 } 3389 #endif 3390 } 3391 DTRACE_PROBE(rdc_sync_loop_rlse_end); 3392 } 3393 threaded: 3394 offset += len; 3395 urdc->sync_pos = offset; 3396 } 3397 3398 sync_done: 3399 sync_completed = 1; 3400 3401 failed: 3402 krdc->group->synccount--; 3403 failed_noincr: 3404 mutex_enter(&sync->lock); 3405 while (sync->complete != sync->threads) { 3406 cv_wait(&sync->cv, &sync->lock); 3407 } 3408 sync->complete = 0; 3409 sync->threads = 0; 3410 mutex_exit(&sync->lock); 3411 3412 /* 3413 * if sync_completed is 0 here, 3414 * we know that the main sync thread failed anyway 3415 * so just free the statuses and fail 3416 */ 3417 if (sync_completed && (_rdc_sync_status_ok(sync_status, &rc) < 0)) { 3418 urdc->sync_pos = rc; 3419 sync_completed = 0; /* at least 1 thread failed */ 3420 } 3421 3422 _rdc_free_sync_status(sync_status); 3423 3424 /* 3425 * we didn't increment, we didn't even sync, 3426 * so don't dec sync_info.active_thr 3427 */ 3428 if (!queuing) { 3429 mutex_enter(&sync_info.lock); 3430 sync_info.active_thr--; 3431 /* LINTED */ 3432 RDC_AVAIL_THR_TUNE(sync_info); 3433 mutex_exit(&sync_info.lock); 3434 } 3435 3436 if (handle) { 3437 (void) nsc_free_buf(handle); 3438 } 3439 3440 if (alloc_h) { 3441 (void) nsc_free_handle(alloc_h); 3442 } 3443 3444 if (reserved) { 3445 _rdc_rlse_devs(krdc, rtype); 3446 } 3447 3448 notstarted: 3449 rdc_group_enter(krdc); 3450 ASSERT(krdc->aux_state & RDC_AUXSYNCIP); 3451 if (IS_STATE(urdc, RDC_QUEUING)) 3452 rdc_clr_flags(urdc, RDC_QUEUING); 3453 3454 if (sync_completed) { 3455 (void) rdc_net_state(krdc->index, CCIO_DONE); 3456 } else { 3457 (void) rdc_net_state(krdc->index, CCIO_ENABLELOG); 3458 } 3459 3460 rdc_clr_flags(urdc, RDC_SYNCING); 3461 if (rdc_get_vflags(urdc) & RDC_SLAVE) { 3462 rdc_many_enter(krdc); 3463 rdc_clr_mflags(urdc, RDC_SLAVE); 3464 rdc_many_exit(krdc); 3465 } 3466 if (krdc->type_flag & RDC_ASYNCMODE) 3467 rdc_set_flags(urdc, RDC_ASYNC); 3468 if (sync_completed) { 3469 rdc_many_enter(krdc); 3470 rdc_clr_mflags(urdc, RDC_RSYNC_NEEDED); 3471 rdc_many_exit(krdc); 3472 } else { 3473 krdc->remote_index = -1; 3474 rdc_set_flags_log(urdc, RDC_LOGGING, "sync failed to complete"); 3475 } 3476 rdc_group_exit(krdc); 3477 rdc_write_state(urdc); 3478 3479 mutex_enter(&net_blk_lock); 3480 if (sync_completed) 3481 krdc->sync_done = RDC_COMPLETED; 3482 else 3483 krdc->sync_done = RDC_FAILED; 3484 cv_broadcast(&krdc->synccv); 3485 mutex_exit(&net_blk_lock); 3486 3487 } 3488 3489 3490 static int 3491 rdc_sync(rdc_config_t *uparms, spcs_s_info_t kstatus) 3492 { 3493 rdc_set_t *rdc_set = uparms->rdc_set; 3494 int options = uparms->options; 3495 int rc = 0; 3496 int busy = 0; 3497 int index; 3498 rdc_k_info_t *krdc; 3499 rdc_u_info_t *urdc; 3500 rdc_k_info_t *kmulti; 3501 rdc_u_info_t *umulti; 3502 rdc_group_t *group; 3503 rdc_srv_t *svp; 3504 int sm, um, md; 3505 int sync_completed = 0; 3506 int thrcount; 3507 3508 mutex_enter(&rdc_conf_lock); 3509 index = rdc_lookup_byname(rdc_set); 3510 if (index >= 0) 3511 krdc = &rdc_k_info[index]; 3512 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 3513 mutex_exit(&rdc_conf_lock); 3514 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file, 3515 rdc_set->secondary.file); 3516 rc = RDC_EALREADY; 3517 goto notstarted; 3518 } 3519 3520 urdc = &rdc_u_info[index]; 3521 group = krdc->group; 3522 set_busy(krdc); 3523 busy = 1; 3524 if ((krdc->type_flag == 0) || (krdc->type_flag & RDC_DISABLEPEND)) { 3525 /* A resume or enable failed or we raced with a teardown */ 3526 mutex_exit(&rdc_conf_lock); 3527 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file, 3528 rdc_set->secondary.file); 3529 rc = RDC_EALREADY; 3530 goto notstarted; 3531 } 3532 mutex_exit(&rdc_conf_lock); 3533 rdc_group_enter(krdc); 3534 3535 if (!IS_STATE(urdc, RDC_LOGGING)) { 3536 spcs_s_add(kstatus, RDC_ESETNOTLOGGING, urdc->secondary.intf, 3537 urdc->secondary.file); 3538 rc = RDC_ENOTLOGGING; 3539 goto notstarted_unlock; 3540 } 3541 3542 if (rdc_check(krdc, rdc_set)) { 3543 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file, 3544 rdc_set->secondary.file); 3545 rc = RDC_EALREADY; 3546 goto notstarted_unlock; 3547 } 3548 3549 if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) { 3550 spcs_s_add(kstatus, RDC_ENOTPRIMARY, rdc_set->primary.intf, 3551 rdc_set->primary.file, rdc_set->secondary.intf, 3552 rdc_set->secondary.file); 3553 rc = RDC_ENOTPRIMARY; 3554 goto notstarted_unlock; 3555 } 3556 3557 if ((options & RDC_OPT_REVERSE) && (IS_STATE(urdc, RDC_QUEUING))) { 3558 /* 3559 * cannot reverse sync when queuing, need to go logging first 3560 */ 3561 spcs_s_add(kstatus, RDC_EQNORSYNC, rdc_set->primary.intf, 3562 rdc_set->primary.file, rdc_set->secondary.intf, 3563 rdc_set->secondary.file); 3564 rc = RDC_EQNORSYNC; 3565 goto notstarted_unlock; 3566 } 3567 3568 svp = krdc->lsrv; 3569 krdc->intf = rdc_add_to_if(svp, &(urdc->primary.addr), 3570 &(urdc->secondary.addr), 1); 3571 3572 if (!krdc->intf) { 3573 spcs_s_add(kstatus, RDC_EADDTOIF, urdc->primary.intf, 3574 urdc->secondary.intf); 3575 rc = RDC_EADDTOIF; 3576 goto notstarted_unlock; 3577 } 3578 3579 if (urdc->volume_size == 0) { 3580 /* Implies reserve failed when previous resume was done */ 3581 rdc_get_details(krdc); 3582 } 3583 if (urdc->volume_size == 0) { 3584 spcs_s_add(kstatus, RDC_ENOBMAP); 3585 rc = RDC_ENOBMAP; 3586 goto notstarted_unlock; 3587 } 3588 3589 if (krdc->dcio_bitmap == NULL) { 3590 if (rdc_resume_bitmap(krdc) < 0) { 3591 spcs_s_add(kstatus, RDC_ENOBMAP); 3592 rc = RDC_ENOBMAP; 3593 goto notstarted_unlock; 3594 } 3595 } 3596 3597 if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd)) { 3598 if (rdc_reset_bitmap(krdc)) { 3599 spcs_s_add(kstatus, RDC_EBITMAP); 3600 rc = RDC_EBITMAP; 3601 goto notstarted_unlock; 3602 } 3603 } 3604 3605 if (IS_MANY(krdc) || IS_MULTI(krdc)) { 3606 rdc_u_info_t *ubad; 3607 3608 if ((ubad = rdc_allow_pri_sync(urdc, options)) != NULL) { 3609 spcs_s_add(kstatus, RDC_ESTATE, 3610 ubad->primary.intf, ubad->primary.file, 3611 ubad->secondary.intf, ubad->secondary.file); 3612 rc = RDC_ESTATE; 3613 goto notstarted_unlock; 3614 } 3615 } 3616 3617 /* 3618 * there is a small window where _rdc_sync is still 3619 * running, but has cleared the RDC_SYNCING flag. 3620 * Use aux_state which is only cleared 3621 * after _rdc_sync had done its 'death' broadcast. 3622 */ 3623 if (krdc->aux_state & RDC_AUXSYNCIP) { 3624 #ifdef DEBUG 3625 if (!rdc_get_vflags(urdc) & RDC_SYNCING) { 3626 cmn_err(CE_WARN, "!rdc_sync: " 3627 "RDC_AUXSYNCIP set, SYNCING off"); 3628 } 3629 #endif 3630 spcs_s_add(kstatus, RDC_ESYNCING, rdc_set->primary.file); 3631 rc = RDC_ESYNCING; 3632 goto notstarted_unlock; 3633 } 3634 if (krdc->disk_status == 1) { 3635 spcs_s_add(kstatus, RDC_ESYNCING, rdc_set->primary.file); 3636 rc = RDC_ESYNCING; 3637 goto notstarted_unlock; 3638 } 3639 3640 if ((options & RDC_OPT_FORWARD) && 3641 (rdc_get_mflags(urdc) & RDC_RSYNC_NEEDED)) { 3642 /* cannot forward sync if a reverse sync is needed */ 3643 spcs_s_add(kstatus, RDC_ERSYNCNEEDED, rdc_set->primary.intf, 3644 rdc_set->primary.file, rdc_set->secondary.intf, 3645 rdc_set->secondary.file); 3646 rc = RDC_ERSYNCNEEDED; 3647 goto notstarted_unlock; 3648 } 3649 3650 urdc->sync_pos = 0; 3651 3652 /* Check if the rdc set is accessible on the remote node */ 3653 if (rdc_net_getstate(krdc, &sm, &um, &md, FALSE) < 0) { 3654 /* 3655 * Remote end may be inaccessible, or the rdc set is not 3656 * enabled at the remote end. 3657 */ 3658 spcs_s_add(kstatus, RDC_ECONNOPEN, urdc->secondary.intf, 3659 urdc->secondary.file); 3660 rc = RDC_ECONNOPEN; 3661 goto notstarted_unlock; 3662 } 3663 if (options & RDC_OPT_REVERSE) 3664 krdc->remote_index = rdc_net_state(index, CCIO_RSYNC); 3665 else 3666 krdc->remote_index = rdc_net_state(index, CCIO_SLAVE); 3667 if (krdc->remote_index < 0) { 3668 /* 3669 * Remote note probably not in a valid state to be synced, 3670 * as the state was fetched OK above. 3671 */ 3672 spcs_s_add(kstatus, RDC_ERSTATE, urdc->secondary.intf, 3673 urdc->secondary.file, urdc->primary.intf, 3674 urdc->primary.file); 3675 rc = RDC_ERSTATE; 3676 goto notstarted_unlock; 3677 } 3678 3679 rc = check_filesize(index, kstatus); 3680 if (rc != 0) { 3681 (void) rdc_net_state(krdc->index, CCIO_ENABLELOG); 3682 goto notstarted_unlock; 3683 } 3684 3685 krdc->sync_done = 0; 3686 3687 mutex_enter(&krdc->bmapmutex); 3688 krdc->aux_state |= RDC_AUXSYNCIP; 3689 mutex_exit(&krdc->bmapmutex); 3690 3691 if (options & RDC_OPT_REVERSE) { 3692 rdc_many_enter(krdc); 3693 rdc_set_mflags(urdc, RDC_SLAVE | RDC_RSYNC_NEEDED); 3694 mutex_enter(&krdc->bmapmutex); 3695 rdc_clr_flags(urdc, RDC_VOL_FAILED); 3696 mutex_exit(&krdc->bmapmutex); 3697 rdc_write_state(urdc); 3698 /* LINTED */ 3699 if (kmulti = krdc->multi_next) { 3700 umulti = &rdc_u_info[kmulti->index]; 3701 if (IS_ENABLED(umulti) && (rdc_get_vflags(umulti) & 3702 (RDC_VOL_FAILED | RDC_SYNC_NEEDED))) { 3703 rdc_clr_flags(umulti, RDC_SYNC_NEEDED); 3704 rdc_clr_flags(umulti, RDC_VOL_FAILED); 3705 rdc_write_state(umulti); 3706 } 3707 } 3708 rdc_many_exit(krdc); 3709 } else { 3710 rdc_clr_flags(urdc, RDC_FCAL_FAILED); 3711 rdc_write_state(urdc); 3712 } 3713 3714 if (options & RDC_OPT_UPDATE) { 3715 ASSERT(urdc->volume_size != 0); 3716 if (rdc_net_getbmap(index, 3717 BMAP_LOG_BYTES(urdc->volume_size)) > 0) { 3718 spcs_s_add(kstatus, RDC_ENOBMAP); 3719 rc = RDC_ENOBMAP; 3720 3721 (void) rdc_net_state(index, CCIO_ENABLELOG); 3722 3723 rdc_clr_flags(urdc, RDC_SYNCING); 3724 if (options & RDC_OPT_REVERSE) { 3725 rdc_many_enter(krdc); 3726 rdc_clr_mflags(urdc, RDC_SLAVE); 3727 rdc_many_exit(krdc); 3728 } 3729 if (krdc->type_flag & RDC_ASYNCMODE) 3730 rdc_set_flags(urdc, RDC_ASYNC); 3731 krdc->remote_index = -1; 3732 rdc_set_flags_log(urdc, RDC_LOGGING, 3733 "failed to read remote bitmap"); 3734 rdc_write_state(urdc); 3735 goto failed; 3736 } 3737 rdc_clr_flags(urdc, RDC_FULL); 3738 } else { 3739 /* 3740 * This is a full sync (not an update sync), mark the 3741 * entire bitmap dirty 3742 */ 3743 (void) RDC_FILL_BITMAP(krdc, FALSE); 3744 3745 rdc_set_flags(urdc, RDC_FULL); 3746 } 3747 3748 rdc_group_exit(krdc); 3749 3750 /* 3751 * allow diskq->memq flusher to wake up 3752 */ 3753 mutex_enter(&krdc->group->ra_queue.net_qlock); 3754 krdc->group->ra_queue.qfflags &= ~RDC_QFILLSLEEP; 3755 mutex_exit(&krdc->group->ra_queue.net_qlock); 3756 3757 /* 3758 * if this is a full sync on a non-diskq set or 3759 * a diskq set that has failed, clear the async flag 3760 */ 3761 if (krdc->type_flag & RDC_ASYNCMODE) { 3762 if ((!(options & RDC_OPT_UPDATE)) || 3763 (!RDC_IS_DISKQ(krdc->group)) || 3764 (!(IS_STATE(urdc, RDC_QUEUING)))) { 3765 /* full syncs, or core queue are synchronous */ 3766 rdc_group_enter(krdc); 3767 rdc_clr_flags(urdc, RDC_ASYNC); 3768 rdc_group_exit(krdc); 3769 } 3770 3771 /* 3772 * if the queue failed because it was full, lets see 3773 * if we can restart it. After _rdc_sync() is done 3774 * the modes will switch and we will begin disk 3775 * queuing again. NOTE: this should only be called 3776 * once per group, as it clears state for all group 3777 * members, also clears the async flag for all members 3778 */ 3779 if (IS_STATE(urdc, RDC_DISKQ_FAILED)) { 3780 rdc_unfail_diskq(krdc); 3781 } else { 3782 /* don't add insult to injury by flushing a dead queue */ 3783 3784 /* 3785 * if we are updating, and a diskq and 3786 * the async thread isn't active, start 3787 * it up. 3788 */ 3789 if ((options & RDC_OPT_UPDATE) && 3790 (IS_STATE(urdc, RDC_QUEUING))) { 3791 rdc_group_enter(krdc); 3792 rdc_clr_flags(urdc, RDC_SYNCING); 3793 rdc_group_exit(krdc); 3794 mutex_enter(&krdc->group->ra_queue.net_qlock); 3795 if (krdc->group->ra_queue.qfill_sleeping == 3796 RDC_QFILL_ASLEEP) 3797 cv_broadcast(&group->ra_queue.qfcv); 3798 mutex_exit(&krdc->group->ra_queue.net_qlock); 3799 thrcount = urdc->asyncthr; 3800 while ((thrcount-- > 0) && 3801 !krdc->group->rdc_writer) { 3802 (void) rdc_writer(krdc->index); 3803 } 3804 } 3805 } 3806 } 3807 3808 /* 3809 * For a reverse sync, merge the current bitmap with all other sets 3810 * that share this volume. 3811 */ 3812 if (options & RDC_OPT_REVERSE) { 3813 retry_many: 3814 rdc_many_enter(krdc); 3815 if (IS_MANY(krdc)) { 3816 rdc_k_info_t *kmany; 3817 rdc_u_info_t *umany; 3818 3819 for (kmany = krdc->many_next; kmany != krdc; 3820 kmany = kmany->many_next) { 3821 umany = &rdc_u_info[kmany->index]; 3822 if (!IS_ENABLED(umany)) 3823 continue; 3824 ASSERT(umany->flags & RDC_PRIMARY); 3825 3826 if (!mutex_tryenter(&kmany->group->lock)) { 3827 rdc_many_exit(krdc); 3828 /* May merge more than once */ 3829 goto retry_many; 3830 } 3831 rdc_merge_bitmaps(krdc, kmany); 3832 mutex_exit(&kmany->group->lock); 3833 } 3834 } 3835 rdc_many_exit(krdc); 3836 3837 retry_multi: 3838 rdc_many_enter(krdc); 3839 if (IS_MULTI(krdc)) { 3840 rdc_k_info_t *kmulti = krdc->multi_next; 3841 rdc_u_info_t *umulti = &rdc_u_info[kmulti->index]; 3842 3843 if (IS_ENABLED(umulti)) { 3844 ASSERT(!(umulti->flags & RDC_PRIMARY)); 3845 3846 if (!mutex_tryenter(&kmulti->group->lock)) { 3847 rdc_many_exit(krdc); 3848 goto retry_multi; 3849 } 3850 rdc_merge_bitmaps(krdc, kmulti); 3851 mutex_exit(&kmulti->group->lock); 3852 } 3853 } 3854 rdc_many_exit(krdc); 3855 } 3856 3857 rdc_group_enter(krdc); 3858 3859 if (krdc->bitmap_write == 0) { 3860 if (rdc_write_bitmap_fill(krdc) >= 0) 3861 krdc->bitmap_write = -1; 3862 } 3863 3864 if (krdc->bitmap_write > 0) 3865 (void) rdc_write_bitmap(krdc); 3866 3867 urdc->bits_set = RDC_COUNT_BITMAP(krdc); 3868 3869 rdc_group_exit(krdc); 3870 3871 if (options & RDC_OPT_REVERSE) { 3872 (void) _rdc_sync_event_notify(RDC_SYNC_START, 3873 urdc->primary.file, urdc->group_name); 3874 } 3875 3876 /* Now set off the sync itself */ 3877 3878 mutex_enter(&net_blk_lock); 3879 if (nsc_create_process( 3880 (void (*)(void *))_rdc_sync, (void *)krdc, FALSE)) { 3881 mutex_exit(&net_blk_lock); 3882 spcs_s_add(kstatus, RDC_ENOPROC); 3883 /* 3884 * We used to just return here, 3885 * but we need to clear the AUXSYNCIP bit 3886 * and there is a very small chance that 3887 * someone may be waiting on the disk_status flag. 3888 */ 3889 rc = RDC_ENOPROC; 3890 /* 3891 * need the group lock held at failed. 3892 */ 3893 rdc_group_enter(krdc); 3894 goto failed; 3895 } 3896 3897 mutex_enter(&rdc_conf_lock); 3898 wakeup_busy(krdc); 3899 busy = 0; 3900 mutex_exit(&rdc_conf_lock); 3901 3902 while (krdc->sync_done == 0) 3903 cv_wait(&krdc->synccv, &net_blk_lock); 3904 mutex_exit(&net_blk_lock); 3905 3906 rdc_group_enter(krdc); 3907 3908 if (krdc->sync_done == RDC_FAILED) { 3909 char siztmp1[16]; 3910 (void) spcs_s_inttostring( 3911 urdc->sync_pos, siztmp1, sizeof (siztmp1), 3912 0); 3913 spcs_s_add(kstatus, RDC_EFAIL, siztmp1); 3914 rc = RDC_EFAIL; 3915 } else 3916 sync_completed = 1; 3917 3918 failed: 3919 /* 3920 * We use this flag now to make halt_sync() wait for 3921 * us to terminate and let us take the group lock. 3922 */ 3923 krdc->aux_state &= ~RDC_AUXSYNCIP; 3924 if (krdc->disk_status == 1) { 3925 krdc->disk_status = 0; 3926 cv_broadcast(&krdc->haltcv); 3927 } 3928 3929 notstarted_unlock: 3930 rdc_group_exit(krdc); 3931 3932 if (sync_completed && (options & RDC_OPT_REVERSE)) { 3933 (void) _rdc_sync_event_notify(RDC_SYNC_DONE, 3934 urdc->primary.file, urdc->group_name); 3935 } 3936 3937 notstarted: 3938 if (busy) { 3939 mutex_enter(&rdc_conf_lock); 3940 wakeup_busy(krdc); 3941 mutex_exit(&rdc_conf_lock); 3942 } 3943 3944 return (rc); 3945 } 3946 3947 /* ARGSUSED */ 3948 static int 3949 _rdc_suspend(rdc_k_info_t *krdc, rdc_set_t *rdc_set, spcs_s_info_t kstatus) 3950 { 3951 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 3952 rdc_if_t *ip; 3953 int index = krdc->index; 3954 3955 ASSERT(krdc->group != NULL); 3956 rdc_group_enter(krdc); 3957 #ifdef DEBUG 3958 ASSERT(rdc_check(krdc, rdc_set) == 0); 3959 #else 3960 if (rdc_check(krdc, rdc_set)) { 3961 rdc_group_exit(krdc); 3962 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file, 3963 rdc_set->secondary.file); 3964 return (RDC_EALREADY); 3965 } 3966 #endif 3967 3968 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 3969 halt_sync(krdc); 3970 ASSERT(IS_ENABLED(urdc)); 3971 } 3972 3973 rdc_group_exit(krdc); 3974 (void) rdc_unintercept(krdc); 3975 3976 #ifdef DEBUG 3977 cmn_err(CE_NOTE, "!SNDR: suspended %s %s", urdc->primary.file, 3978 urdc->secondary.file); 3979 #endif 3980 3981 /* Configured but not enabled */ 3982 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 3983 3984 3985 if (IS_ASYNC(urdc) && !RDC_IS_DISKQ(krdc->group)) { 3986 int tries = 2; /* in case of possibly stuck flusher threads */ 3987 #ifdef DEBUG 3988 net_queue *qp = &krdc->group->ra_queue; 3989 #endif 3990 do { 3991 if (!krdc->group->rdc_writer) 3992 (void) rdc_writer(krdc->index); 3993 3994 (void) rdc_drain_queue(krdc->index); 3995 3996 } while (krdc->group->rdc_writer && tries--); 3997 3998 /* ok, force it to happen... */ 3999 if (rdc_drain_queue(krdc->index) != 0) { 4000 do { 4001 mutex_enter(&krdc->group->ra_queue.net_qlock); 4002 krdc->group->asyncdis = 1; 4003 cv_broadcast(&krdc->group->asyncqcv); 4004 mutex_exit(&krdc->group->ra_queue.net_qlock); 4005 cmn_err(CE_WARN, 4006 "!SNDR: async I/O pending and not flushed " 4007 "for %s during suspend", 4008 urdc->primary.file); 4009 #ifdef DEBUG 4010 cmn_err(CE_WARN, 4011 "!nitems: %" NSC_SZFMT " nblocks: %" 4012 NSC_SZFMT " head: 0x%p tail: 0x%p", 4013 qp->nitems, qp->blocks, 4014 (void *)qp->net_qhead, 4015 (void *)qp->net_qtail); 4016 #endif 4017 } while (krdc->group->rdc_thrnum > 0); 4018 } 4019 } 4020 4021 mutex_enter(&rdc_conf_lock); 4022 ip = krdc->intf; 4023 krdc->intf = 0; 4024 4025 if (ip) { 4026 rdc_remove_from_if(ip); 4027 } 4028 4029 mutex_exit(&rdc_conf_lock); 4030 4031 rdc_group_enter(krdc); 4032 4033 /* Configured but not enabled */ 4034 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4035 4036 rdc_group_exit(krdc); 4037 /* Must not hold group lock during this function */ 4038 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN) 4039 delay(2); 4040 rdc_group_enter(krdc); 4041 4042 /* Don't rdc_clear_state, unlike _rdc_disable */ 4043 4044 rdc_free_bitmap(krdc, RDC_CMD_SUSPEND); 4045 rdc_close_bitmap(krdc); 4046 4047 rdc_dev_close(krdc); 4048 rdc_close_direct(krdc); 4049 4050 /* Configured but not enabled */ 4051 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4052 4053 rdc_group_exit(krdc); 4054 4055 /* 4056 * we should now unregister the queue, with no conflicting 4057 * locks held. This is the last(only) member of the group 4058 */ 4059 if (krdc->group && RDC_IS_DISKQ(krdc->group) && 4060 krdc->group->count == 1) { /* stop protecting queue */ 4061 rdc_unintercept_diskq(krdc->group); 4062 } 4063 4064 mutex_enter(&rdc_conf_lock); 4065 4066 /* Configured but not enabled */ 4067 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4068 4069 wait_busy(krdc); 4070 4071 if (IS_MANY(krdc) || IS_MULTI(krdc)) 4072 remove_from_many(krdc); 4073 4074 remove_from_group(krdc); 4075 4076 krdc->remote_index = -1; 4077 ASSERT(krdc->type_flag & RDC_CONFIGURED); 4078 ASSERT(krdc->type_flag & RDC_DISABLEPEND); 4079 krdc->type_flag = 0; 4080 #ifdef DEBUG 4081 if (krdc->dcio_bitmap) 4082 cmn_err(CE_WARN, "!_rdc_suspend: possible mem leak, " 4083 "dcio_bitmap"); 4084 #endif 4085 krdc->dcio_bitmap = NULL; 4086 krdc->bitmap_ref = NULL; 4087 krdc->bitmap_size = 0; 4088 krdc->maxfbas = 0; 4089 krdc->bitmap_write = 0; 4090 krdc->disk_status = 0; 4091 rdc_destroy_svinfo(krdc->lsrv); 4092 krdc->lsrv = NULL; 4093 krdc->multi_next = NULL; 4094 4095 rdc_u_init(urdc); 4096 4097 mutex_exit(&rdc_conf_lock); 4098 rdc_kstat_delete(index); 4099 return (0); 4100 } 4101 4102 static int 4103 rdc_suspend(rdc_config_t *uparms, spcs_s_info_t kstatus) 4104 { 4105 rdc_k_info_t *krdc; 4106 int index; 4107 int rc; 4108 4109 mutex_enter(&rdc_conf_lock); 4110 4111 index = rdc_lookup_byname(uparms->rdc_set); 4112 if (index >= 0) 4113 krdc = &rdc_k_info[index]; 4114 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 4115 mutex_exit(&rdc_conf_lock); 4116 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 4117 uparms->rdc_set->secondary.file); 4118 return (RDC_EALREADY); 4119 } 4120 4121 krdc->type_flag |= RDC_DISABLEPEND; 4122 wait_busy(krdc); 4123 if (krdc->type_flag == 0) { 4124 /* A resume or enable failed */ 4125 mutex_exit(&rdc_conf_lock); 4126 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 4127 uparms->rdc_set->secondary.file); 4128 return (RDC_EALREADY); 4129 } 4130 mutex_exit(&rdc_conf_lock); 4131 4132 rc = _rdc_suspend(krdc, uparms->rdc_set, kstatus); 4133 return (rc); 4134 } 4135 4136 static int 4137 _rdc_resume(rdc_set_t *rdc_set, int options, spcs_s_info_t kstatus) 4138 { 4139 int index; 4140 char *rhost; 4141 struct netbuf *addrp; 4142 rdc_k_info_t *krdc; 4143 rdc_u_info_t *urdc; 4144 rdc_srv_t *svp = NULL; 4145 char *local_file; 4146 char *local_bitmap; 4147 int rc, rc1; 4148 nsc_size_t maxfbas; 4149 rdc_group_t *grp; 4150 4151 if ((rdc_set->primary.intf[0] == 0) || 4152 (rdc_set->primary.addr.len == 0) || 4153 (rdc_set->primary.file[0] == 0) || 4154 (rdc_set->primary.bitmap[0] == 0) || 4155 (rdc_set->secondary.intf[0] == 0) || 4156 (rdc_set->secondary.addr.len == 0) || 4157 (rdc_set->secondary.file[0] == 0) || 4158 (rdc_set->secondary.bitmap[0] == 0)) { 4159 spcs_s_add(kstatus, RDC_EEMPTY); 4160 return (RDC_EEMPTY); 4161 } 4162 4163 /* Next check there aren't any enabled rdc sets which match. */ 4164 4165 mutex_enter(&rdc_conf_lock); 4166 4167 if (rdc_lookup_byname(rdc_set) >= 0) { 4168 mutex_exit(&rdc_conf_lock); 4169 spcs_s_add(kstatus, RDC_EENABLED, rdc_set->primary.intf, 4170 rdc_set->primary.file, rdc_set->secondary.intf, 4171 rdc_set->secondary.file); 4172 return (RDC_EENABLED); 4173 } 4174 4175 if (rdc_lookup_many2one(rdc_set) >= 0) { 4176 mutex_exit(&rdc_conf_lock); 4177 spcs_s_add(kstatus, RDC_EMANY2ONE, rdc_set->primary.intf, 4178 rdc_set->primary.file, rdc_set->secondary.intf, 4179 rdc_set->secondary.file); 4180 return (RDC_EMANY2ONE); 4181 } 4182 4183 if (rdc_set->netconfig->knc_proto == NULL) { 4184 mutex_exit(&rdc_conf_lock); 4185 spcs_s_add(kstatus, RDC_ENETCONFIG); 4186 return (RDC_ENETCONFIG); 4187 } 4188 4189 if (rdc_set->primary.addr.len == 0) { 4190 mutex_exit(&rdc_conf_lock); 4191 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->primary.file); 4192 return (RDC_ENETBUF); 4193 } 4194 4195 if (rdc_set->secondary.addr.len == 0) { 4196 mutex_exit(&rdc_conf_lock); 4197 spcs_s_add(kstatus, RDC_ENETBUF, rdc_set->secondary.file); 4198 return (RDC_ENETBUF); 4199 } 4200 4201 /* Check that the local data volume isn't in use as a bitmap */ 4202 if (options & RDC_OPT_PRIMARY) 4203 local_file = rdc_set->primary.file; 4204 else 4205 local_file = rdc_set->secondary.file; 4206 if (rdc_lookup_bitmap(local_file) >= 0) { 4207 mutex_exit(&rdc_conf_lock); 4208 spcs_s_add(kstatus, RDC_EVOLINUSE, local_file); 4209 return (RDC_EVOLINUSE); 4210 } 4211 4212 /* check that the secondary data volume isn't in use */ 4213 if (!(options & RDC_OPT_PRIMARY)) { 4214 local_file = rdc_set->secondary.file; 4215 if (rdc_lookup_secondary(local_file) >= 0) { 4216 mutex_exit(&rdc_conf_lock); 4217 spcs_s_add(kstatus, RDC_EVOLINUSE, local_file); 4218 return (RDC_EVOLINUSE); 4219 } 4220 } 4221 4222 /* Check that the bitmap isn't in use as a data volume */ 4223 if (options & RDC_OPT_PRIMARY) 4224 local_bitmap = rdc_set->primary.bitmap; 4225 else 4226 local_bitmap = rdc_set->secondary.bitmap; 4227 if (rdc_lookup_configured(local_bitmap) >= 0) { 4228 mutex_exit(&rdc_conf_lock); 4229 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap); 4230 return (RDC_EBMPINUSE); 4231 } 4232 4233 /* Check that the bitmap isn't already in use as a bitmap */ 4234 if (rdc_lookup_bitmap(local_bitmap) >= 0) { 4235 mutex_exit(&rdc_conf_lock); 4236 spcs_s_add(kstatus, RDC_EBMPINUSE, local_bitmap); 4237 return (RDC_EBMPINUSE); 4238 } 4239 4240 /* Set urdc->volume_size */ 4241 index = rdc_dev_open(rdc_set, options); 4242 if (index < 0) { 4243 mutex_exit(&rdc_conf_lock); 4244 if (options & RDC_OPT_PRIMARY) 4245 spcs_s_add(kstatus, RDC_EOPEN, rdc_set->primary.intf, 4246 rdc_set->primary.file); 4247 else 4248 spcs_s_add(kstatus, RDC_EOPEN, rdc_set->secondary.intf, 4249 rdc_set->secondary.file); 4250 return (RDC_EOPEN); 4251 } 4252 4253 urdc = &rdc_u_info[index]; 4254 krdc = &rdc_k_info[index]; 4255 4256 /* copy relevant parts of rdc_set to urdc field by field */ 4257 4258 (void) strncpy(urdc->primary.intf, rdc_set->primary.intf, 4259 MAX_RDC_HOST_SIZE); 4260 (void) strncpy(urdc->secondary.intf, rdc_set->secondary.intf, 4261 MAX_RDC_HOST_SIZE); 4262 4263 (void) strncpy(urdc->group_name, rdc_set->group_name, NSC_MAXPATH); 4264 4265 dup_rdc_netbuf(&rdc_set->primary.addr, &urdc->primary.addr); 4266 (void) strncpy(urdc->primary.file, rdc_set->primary.file, NSC_MAXPATH); 4267 (void) strncpy(urdc->primary.bitmap, rdc_set->primary.bitmap, 4268 NSC_MAXPATH); 4269 4270 dup_rdc_netbuf(&rdc_set->secondary.addr, &urdc->secondary.addr); 4271 (void) strncpy(urdc->secondary.file, rdc_set->secondary.file, 4272 NSC_MAXPATH); 4273 (void) strncpy(urdc->secondary.bitmap, rdc_set->secondary.bitmap, 4274 NSC_MAXPATH); 4275 (void) strncpy(urdc->disk_queue, rdc_set->disk_queue, NSC_MAXPATH); 4276 urdc->setid = rdc_set->setid; 4277 4278 if ((options & RDC_OPT_SYNC) && urdc->disk_queue[0]) { 4279 mutex_exit(&rdc_conf_lock); 4280 rdc_dev_close(krdc); 4281 spcs_s_add(kstatus, RDC_EQWRONGMODE); 4282 return (RDC_EQWRONGMODE); 4283 } 4284 4285 /* 4286 * init flags now so that state left by failures in add_to_group() 4287 * are preserved. 4288 */ 4289 rdc_init_flags(urdc); 4290 4291 if ((rc1 = add_to_group(krdc, options, RDC_CMD_RESUME)) != 0) { 4292 if (rc1 == RDC_EQNOADD) { /* something went wrong with queue */ 4293 rdc_fail_diskq(krdc, RDC_WAIT, RDC_NOLOG); 4294 /* don't return a failure here, continue with resume */ 4295 4296 } else { /* some other group add failure */ 4297 mutex_exit(&rdc_conf_lock); 4298 rdc_dev_close(krdc); 4299 spcs_s_add(kstatus, RDC_EGROUP, 4300 rdc_set->primary.intf, rdc_set->primary.file, 4301 rdc_set->secondary.intf, rdc_set->secondary.file, 4302 rdc_set->group_name); 4303 return (RDC_EGROUP); 4304 } 4305 } 4306 4307 /* 4308 * maxfbas was set in rdc_dev_open as primary's maxfbas. 4309 * If diskq's maxfbas is smaller, then use diskq's. 4310 */ 4311 grp = krdc->group; 4312 if (grp && RDC_IS_DISKQ(grp) && (grp->diskqfd != 0)) { 4313 rc = _rdc_rsrv_diskq(grp); 4314 if (RDC_SUCCESS(rc)) { 4315 rc = nsc_maxfbas(grp->diskqfd, 0, &maxfbas); 4316 if (rc == 0) { 4317 #ifdef DEBUG 4318 if (krdc->maxfbas != maxfbas) 4319 cmn_err(CE_NOTE, 4320 "!_rdc_resume: diskq maxfbas = %" 4321 NSC_SZFMT ", primary maxfbas = %" 4322 NSC_SZFMT, maxfbas, krdc->maxfbas); 4323 #endif 4324 krdc->maxfbas = min(krdc->maxfbas, 4325 maxfbas); 4326 } else { 4327 cmn_err(CE_WARN, 4328 "!_rdc_resume: diskq maxfbas failed (%d)", 4329 rc); 4330 } 4331 _rdc_rlse_diskq(grp); 4332 } else { 4333 cmn_err(CE_WARN, 4334 "!_rdc_resume: diskq reserve failed (%d)", rc); 4335 } 4336 } 4337 4338 (void) strncpy(urdc->direct_file, rdc_set->direct_file, NSC_MAXPATH); 4339 if ((options & RDC_OPT_PRIMARY) && rdc_set->direct_file[0]) { 4340 if (rdc_open_direct(krdc) == NULL) 4341 rdc_set_flags(urdc, RDC_FCAL_FAILED); 4342 } 4343 4344 krdc->many_next = krdc; 4345 4346 ASSERT(krdc->type_flag == 0); 4347 krdc->type_flag = RDC_CONFIGURED; 4348 4349 if (options & RDC_OPT_PRIMARY) 4350 rdc_set_flags(urdc, RDC_PRIMARY); 4351 4352 if (options & RDC_OPT_ASYNC) 4353 krdc->type_flag |= RDC_ASYNCMODE; 4354 4355 set_busy(krdc); 4356 4357 urdc->syshostid = rdc_set->syshostid; 4358 4359 if (add_to_many(krdc) < 0) { 4360 mutex_exit(&rdc_conf_lock); 4361 4362 rdc_group_enter(krdc); 4363 4364 spcs_s_add(kstatus, RDC_EMULTI); 4365 rc = RDC_EMULTI; 4366 goto fail; 4367 } 4368 4369 /* Configured but not enabled */ 4370 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4371 4372 mutex_exit(&rdc_conf_lock); 4373 4374 if (urdc->volume_size == 0) { 4375 rdc_many_enter(krdc); 4376 if (options & RDC_OPT_PRIMARY) 4377 rdc_set_mflags(urdc, RDC_RSYNC_NEEDED); 4378 else 4379 rdc_set_flags(urdc, RDC_SYNC_NEEDED); 4380 rdc_set_flags(urdc, RDC_VOL_FAILED); 4381 rdc_many_exit(krdc); 4382 } 4383 4384 rdc_group_enter(krdc); 4385 4386 /* Configured but not enabled */ 4387 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4388 4389 /* 4390 * The rdc set is configured but not yet enabled. Other operations must 4391 * ignore this set until it is enabled. 4392 */ 4393 4394 urdc->sync_pos = 0; 4395 4396 /* Set tunable defaults, we'll pick up tunables from the header later */ 4397 4398 urdc->maxqfbas = rdc_maxthres_queue; 4399 urdc->maxqitems = rdc_max_qitems; 4400 urdc->autosync = 0; 4401 urdc->asyncthr = rdc_asyncthr; 4402 4403 urdc->netconfig = rdc_set->netconfig; 4404 4405 if (options & RDC_OPT_PRIMARY) { 4406 rhost = rdc_set->secondary.intf; 4407 addrp = &rdc_set->secondary.addr; 4408 } else { 4409 rhost = rdc_set->primary.intf; 4410 addrp = &rdc_set->primary.addr; 4411 } 4412 4413 if (options & RDC_OPT_ASYNC) 4414 rdc_set_flags(urdc, RDC_ASYNC); 4415 4416 svp = rdc_create_svinfo(rhost, addrp, urdc->netconfig); 4417 if (svp == NULL) { 4418 spcs_s_add(kstatus, ENOMEM); 4419 rc = ENOMEM; 4420 goto fail; 4421 } 4422 4423 urdc->netconfig = NULL; /* This will be no good soon */ 4424 4425 /* Don't set krdc->intf here */ 4426 rdc_kstat_create(index); 4427 4428 /* if the bitmap resume isn't clean, it will clear queuing flag */ 4429 4430 (void) rdc_resume_bitmap(krdc); 4431 4432 if (RDC_IS_DISKQ(krdc->group)) { 4433 disk_queue *q = &krdc->group->diskq; 4434 if ((rc1 == RDC_EQNOADD) || 4435 IS_QSTATE(q, RDC_QBADRESUME)) { 4436 rdc_clr_flags(urdc, RDC_QUEUING); 4437 RDC_ZERO_BITREF(krdc); 4438 } 4439 } 4440 4441 if (krdc->lsrv == NULL) 4442 krdc->lsrv = svp; 4443 else { 4444 #ifdef DEBUG 4445 cmn_err(CE_WARN, "!_rdc_resume: krdc->lsrv already set: %p", 4446 (void *) krdc->lsrv); 4447 #endif 4448 rdc_destroy_svinfo(svp); 4449 } 4450 svp = NULL; 4451 4452 /* Configured but not enabled */ 4453 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4454 4455 /* And finally */ 4456 4457 krdc->remote_index = -1; 4458 4459 /* Should we set the whole group logging? */ 4460 rdc_set_flags(urdc, RDC_ENABLED | RDC_LOGGING); 4461 4462 rdc_group_exit(krdc); 4463 4464 if (rdc_intercept(krdc) != 0) { 4465 rdc_group_enter(krdc); 4466 rdc_clr_flags(urdc, RDC_ENABLED); 4467 if (options & RDC_OPT_PRIMARY) 4468 spcs_s_add(kstatus, RDC_EREGISTER, urdc->primary.file); 4469 else 4470 spcs_s_add(kstatus, RDC_EREGISTER, 4471 urdc->secondary.file); 4472 #ifdef DEBUG 4473 cmn_err(CE_NOTE, "!nsc_register_path failed %s", 4474 urdc->primary.file); 4475 #endif 4476 rc = RDC_EREGISTER; 4477 goto bmpfail; 4478 } 4479 #ifdef DEBUG 4480 cmn_err(CE_NOTE, "!SNDR: resumed %s %s", urdc->primary.file, 4481 urdc->secondary.file); 4482 #endif 4483 4484 rdc_write_state(urdc); 4485 4486 mutex_enter(&rdc_conf_lock); 4487 wakeup_busy(krdc); 4488 mutex_exit(&rdc_conf_lock); 4489 4490 return (0); 4491 4492 bmpfail: 4493 if (options & RDC_OPT_PRIMARY) 4494 spcs_s_add(kstatus, RDC_EBITMAP, urdc->primary.bitmap); 4495 else 4496 spcs_s_add(kstatus, RDC_EBITMAP, urdc->secondary.bitmap); 4497 rc = RDC_EBITMAP; 4498 if (rdc_get_vflags(urdc) & RDC_ENABLED) { 4499 rdc_group_exit(krdc); 4500 (void) rdc_unintercept(krdc); 4501 rdc_group_enter(krdc); 4502 } 4503 4504 fail: 4505 rdc_kstat_delete(index); 4506 /* Don't unset krdc->intf here, unlike _rdc_enable */ 4507 4508 /* Configured but not enabled */ 4509 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4510 4511 rdc_dev_close(krdc); 4512 rdc_close_direct(krdc); 4513 rdc_destroy_svinfo(svp); 4514 4515 /* Configured but not enabled */ 4516 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4517 4518 rdc_group_exit(krdc); 4519 4520 mutex_enter(&rdc_conf_lock); 4521 4522 /* Configured but not enabled */ 4523 ASSERT(IS_CONFIGURED(krdc) && !IS_ENABLED(urdc)); 4524 4525 remove_from_group(krdc); 4526 4527 if (IS_MANY(krdc) || IS_MULTI(krdc)) 4528 remove_from_many(krdc); 4529 4530 rdc_u_init(urdc); 4531 4532 ASSERT(krdc->type_flag & RDC_CONFIGURED); 4533 krdc->type_flag = 0; 4534 wakeup_busy(krdc); 4535 4536 mutex_exit(&rdc_conf_lock); 4537 4538 return (rc); 4539 } 4540 4541 static int 4542 rdc_resume(rdc_config_t *uparms, spcs_s_info_t kstatus) 4543 { 4544 char itmp[10]; 4545 int rc; 4546 4547 if (!(uparms->options & RDC_OPT_SYNC) && 4548 !(uparms->options & RDC_OPT_ASYNC)) { 4549 (void) spcs_s_inttostring( 4550 uparms->options, itmp, sizeof (itmp), 1); 4551 spcs_s_add(kstatus, RDC_EEINVAL, itmp); 4552 rc = RDC_EEINVAL; 4553 goto done; 4554 } 4555 4556 if (!(uparms->options & RDC_OPT_PRIMARY) && 4557 !(uparms->options & RDC_OPT_SECONDARY)) { 4558 (void) spcs_s_inttostring( 4559 uparms->options, itmp, sizeof (itmp), 1); 4560 spcs_s_add(kstatus, RDC_EEINVAL, itmp); 4561 rc = RDC_EEINVAL; 4562 goto done; 4563 } 4564 4565 rc = _rdc_resume(uparms->rdc_set, uparms->options, kstatus); 4566 done: 4567 return (rc); 4568 } 4569 4570 /* 4571 * if rdc_group_log is called because a volume has failed, 4572 * we must disgard the queue to preserve write ordering. 4573 * later perhaps, we can keep queuing, but we would have to 4574 * rewrite the i/o path to acommodate that. currently, if there 4575 * is a volume failure, the buffers are satisfied remotely and 4576 * there is no way to satisfy them from the current diskq config 4577 * phew, if we do that.. it will be difficult 4578 */ 4579 int 4580 rdc_can_queue(rdc_k_info_t *krdc) 4581 { 4582 rdc_k_info_t *p; 4583 rdc_u_info_t *q; 4584 4585 for (p = krdc->group_next; ; p = p->group_next) { 4586 q = &rdc_u_info[p->index]; 4587 if (IS_STATE(q, RDC_VOL_FAILED)) 4588 return (0); 4589 if (p == krdc) 4590 break; 4591 } 4592 return (1); 4593 } 4594 4595 /* 4596 * wait here, until all in flight async i/o's have either 4597 * finished or failed. Avoid the race with r_net_state() 4598 * which tells remote end to log. 4599 */ 4600 void 4601 rdc_inflwait(rdc_group_t *grp) 4602 { 4603 int bail = RDC_CLNT_TMOUT * 2; /* to include retries */ 4604 volatile int *inflitems; 4605 4606 if (RDC_IS_DISKQ(grp)) 4607 inflitems = (&(grp->diskq.inflitems)); 4608 else 4609 inflitems = (&(grp->ra_queue.inflitems)); 4610 4611 while (*inflitems && (--bail > 0)) 4612 delay(HZ); 4613 } 4614 4615 void 4616 rdc_group_log(rdc_k_info_t *krdc, int flag, char *why) 4617 { 4618 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 4619 rdc_k_info_t *p; 4620 rdc_u_info_t *q; 4621 int do_group; 4622 int sm, um, md; 4623 disk_queue *dq; 4624 4625 void (*flag_op)(rdc_u_info_t *urdc, int flag); 4626 4627 ASSERT(MUTEX_HELD(&krdc->group->lock)); 4628 4629 if (!IS_ENABLED(urdc)) 4630 return; 4631 4632 rdc_many_enter(krdc); 4633 4634 if ((flag & RDC_QUEUING) && (!IS_STATE(urdc, RDC_SYNCING)) && 4635 (rdc_can_queue(krdc))) { 4636 flag_op = rdc_set_flags; /* keep queuing, link error */ 4637 flag &= ~RDC_FLUSH; 4638 } else { 4639 flag_op = rdc_clr_flags; /* stop queuing, user request */ 4640 } 4641 4642 do_group = 1; 4643 if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) 4644 do_group = 0; 4645 else if ((urdc->group_name[0] == 0) || 4646 (rdc_get_vflags(urdc) & RDC_LOGGING) || 4647 (rdc_get_vflags(urdc) & RDC_SYNCING)) 4648 do_group = 0; 4649 if (do_group) { 4650 for (p = krdc->group_next; p != krdc; p = p->group_next) { 4651 q = &rdc_u_info[p->index]; 4652 if (!IS_ENABLED(q)) 4653 continue; 4654 if ((rdc_get_vflags(q) & RDC_LOGGING) || 4655 (rdc_get_vflags(q) & RDC_SYNCING)) { 4656 do_group = 0; 4657 break; 4658 } 4659 } 4660 } 4661 if (!do_group && (flag & RDC_FORCE_GROUP)) 4662 do_group = 1; 4663 4664 rdc_many_exit(krdc); 4665 dq = &krdc->group->diskq; 4666 if (do_group) { 4667 #ifdef DEBUG 4668 cmn_err(CE_NOTE, "!SNDR:Group point-in-time for grp: %s %s:%s", 4669 urdc->group_name, urdc->primary.intf, urdc->secondary.intf); 4670 #endif 4671 DTRACE_PROBE(rdc_diskq_group_PIT); 4672 4673 /* Set group logging at the same PIT under rdc_many_lock */ 4674 rdc_many_enter(krdc); 4675 rdc_set_flags_log(urdc, RDC_LOGGING, why); 4676 if (RDC_IS_DISKQ(krdc->group)) 4677 flag_op(urdc, RDC_QUEUING); 4678 for (p = krdc->group_next; p != krdc; p = p->group_next) { 4679 q = &rdc_u_info[p->index]; 4680 if (!IS_ENABLED(q)) 4681 continue; 4682 rdc_set_flags_log(q, RDC_LOGGING, 4683 "consistency group member following leader"); 4684 if (RDC_IS_DISKQ(p->group)) 4685 flag_op(q, RDC_QUEUING); 4686 } 4687 4688 rdc_many_exit(krdc); 4689 4690 /* 4691 * This can cause the async threads to fail, 4692 * which in turn will call rdc_group_log() 4693 * again. Release the lock and re-aquire. 4694 */ 4695 rdc_group_exit(krdc); 4696 4697 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN) 4698 delay(2); 4699 if (!RDC_IS_DISKQ(krdc->group)) 4700 RDC_ZERO_BITREF(krdc); 4701 4702 rdc_inflwait(krdc->group); 4703 4704 /* 4705 * a little lazy, but neat. recall dump_alloc_bufs to 4706 * ensure that the queue pointers & seq are reset properly 4707 * after we have waited for inflight stuff 4708 */ 4709 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN) 4710 delay(2); 4711 4712 rdc_group_enter(krdc); 4713 if (RDC_IS_DISKQ(krdc->group) && (!(flag & RDC_QUEUING))) { 4714 /* fail or user request */ 4715 RDC_ZERO_BITREF(krdc); 4716 mutex_enter(&krdc->group->diskq.disk_qlock); 4717 rdc_init_diskq_header(krdc->group, 4718 &krdc->group->diskq.disk_hdr); 4719 SET_QNXTIO(dq, QHEAD(dq)); 4720 mutex_exit(&krdc->group->diskq.disk_qlock); 4721 } 4722 4723 if (flag & RDC_ALLREMOTE) { 4724 /* Tell other node to start logging */ 4725 if (krdc->lsrv && krdc->intf && !krdc->intf->if_down) 4726 (void) rdc_net_state(krdc->index, 4727 CCIO_ENABLELOG); 4728 } 4729 4730 if (flag & (RDC_ALLREMOTE | RDC_OTHERREMOTE)) { 4731 rdc_many_enter(krdc); 4732 for (p = krdc->group_next; p != krdc; 4733 p = p->group_next) { 4734 if (p->lsrv && krdc->intf && 4735 !krdc->intf->if_down) { 4736 (void) rdc_net_state(p->index, 4737 CCIO_ENABLELOG); 4738 } 4739 } 4740 rdc_many_exit(krdc); 4741 } 4742 4743 rdc_write_state(urdc); 4744 for (p = krdc->group_next; p != krdc; p = p->group_next) { 4745 q = &rdc_u_info[p->index]; 4746 if (!IS_ENABLED(q)) 4747 continue; 4748 rdc_write_state(q); 4749 } 4750 } else { 4751 /* No point in time is possible, just deal with single set */ 4752 4753 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 4754 halt_sync(krdc); 4755 } else { 4756 if (rdc_net_getstate(krdc, &sm, &um, &md, TRUE) < 0) { 4757 rdc_clr_flags(urdc, RDC_SYNCING); 4758 rdc_set_flags_log(urdc, RDC_LOGGING, 4759 "failed to read remote state"); 4760 4761 rdc_write_state(urdc); 4762 while (rdc_dump_alloc_bufs_cd(krdc->index) 4763 == EAGAIN) 4764 delay(2); 4765 if ((RDC_IS_DISKQ(krdc->group)) && 4766 (!(flag & RDC_QUEUING))) { /* fail! */ 4767 mutex_enter(QLOCK(dq)); 4768 rdc_init_diskq_header(krdc->group, 4769 &krdc->group->diskq.disk_hdr); 4770 SET_QNXTIO(dq, QHEAD(dq)); 4771 mutex_exit(QLOCK(dq)); 4772 } 4773 4774 return; 4775 } 4776 } 4777 4778 if (rdc_get_vflags(urdc) & RDC_SYNCING) 4779 return; 4780 4781 if (RDC_IS_DISKQ(krdc->group)) 4782 flag_op(urdc, RDC_QUEUING); 4783 4784 if ((RDC_IS_DISKQ(krdc->group)) && 4785 (!(flag & RDC_QUEUING))) { /* fail! */ 4786 RDC_ZERO_BITREF(krdc); 4787 mutex_enter(QLOCK(dq)); 4788 rdc_init_diskq_header(krdc->group, 4789 &krdc->group->diskq.disk_hdr); 4790 SET_QNXTIO(dq, QHEAD(dq)); 4791 mutex_exit(QLOCK(dq)); 4792 } 4793 4794 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) { 4795 rdc_set_flags_log(urdc, RDC_LOGGING, why); 4796 4797 rdc_write_state(urdc); 4798 4799 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN) 4800 delay(2); 4801 if (!RDC_IS_DISKQ(krdc->group)) 4802 RDC_ZERO_BITREF(krdc); 4803 4804 rdc_inflwait(krdc->group); 4805 /* 4806 * a little lazy, but neat. recall dump_alloc_bufs to 4807 * ensure that the queue pointers & seq are reset 4808 * properly after we have waited for inflight stuff 4809 */ 4810 while (rdc_dump_alloc_bufs_cd(krdc->index) == EAGAIN) 4811 delay(2); 4812 4813 if (flag & RDC_ALLREMOTE) { 4814 /* Tell other node to start logging */ 4815 if (krdc->lsrv && krdc->intf && 4816 !krdc->intf->if_down) { 4817 (void) rdc_net_state(krdc->index, 4818 CCIO_ENABLELOG); 4819 } 4820 } 4821 } 4822 } 4823 /* 4824 * just in case any threads were in flight during log cleanup 4825 */ 4826 if (RDC_IS_DISKQ(krdc->group)) { 4827 mutex_enter(QLOCK(dq)); 4828 cv_broadcast(&dq->qfullcv); 4829 mutex_exit(QLOCK(dq)); 4830 } 4831 } 4832 4833 static int 4834 _rdc_log(rdc_k_info_t *krdc, rdc_set_t *rdc_set, spcs_s_info_t kstatus) 4835 { 4836 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 4837 rdc_srv_t *svp; 4838 4839 rdc_group_enter(krdc); 4840 if (rdc_check(krdc, rdc_set)) { 4841 rdc_group_exit(krdc); 4842 spcs_s_add(kstatus, RDC_EALREADY, rdc_set->primary.file, 4843 rdc_set->secondary.file); 4844 return (RDC_EALREADY); 4845 } 4846 4847 svp = krdc->lsrv; 4848 if (rdc_get_vflags(urdc) & RDC_PRIMARY) 4849 krdc->intf = rdc_add_to_if(svp, &(urdc->primary.addr), 4850 &(urdc->secondary.addr), 1); 4851 else 4852 krdc->intf = rdc_add_to_if(svp, &(urdc->secondary.addr), 4853 &(urdc->primary.addr), 0); 4854 4855 if (!krdc->intf) { 4856 rdc_group_exit(krdc); 4857 spcs_s_add(kstatus, RDC_EADDTOIF, urdc->primary.intf, 4858 urdc->secondary.intf); 4859 return (RDC_EADDTOIF); 4860 } 4861 4862 rdc_group_log(krdc, RDC_FLUSH | RDC_ALLREMOTE, NULL); 4863 4864 if (rdc_get_vflags(urdc) & RDC_SYNCING) { 4865 rdc_group_exit(krdc); 4866 spcs_s_add(kstatus, RDC_ESYNCING, urdc->primary.file); 4867 return (RDC_ESYNCING); 4868 } 4869 4870 rdc_group_exit(krdc); 4871 4872 return (0); 4873 } 4874 4875 static int 4876 rdc_log(rdc_config_t *uparms, spcs_s_info_t kstatus) 4877 { 4878 rdc_k_info_t *krdc; 4879 int rc = 0; 4880 int index; 4881 4882 mutex_enter(&rdc_conf_lock); 4883 index = rdc_lookup_byname(uparms->rdc_set); 4884 if (index >= 0) 4885 krdc = &rdc_k_info[index]; 4886 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 4887 mutex_exit(&rdc_conf_lock); 4888 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 4889 uparms->rdc_set->secondary.file); 4890 return (RDC_EALREADY); 4891 } 4892 4893 set_busy(krdc); 4894 if (krdc->type_flag == 0) { 4895 /* A resume or enable failed */ 4896 wakeup_busy(krdc); 4897 mutex_exit(&rdc_conf_lock); 4898 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 4899 uparms->rdc_set->secondary.file); 4900 return (RDC_EALREADY); 4901 } 4902 mutex_exit(&rdc_conf_lock); 4903 4904 rc = _rdc_log(krdc, uparms->rdc_set, kstatus); 4905 4906 mutex_enter(&rdc_conf_lock); 4907 wakeup_busy(krdc); 4908 mutex_exit(&rdc_conf_lock); 4909 4910 return (rc); 4911 } 4912 4913 4914 static int 4915 rdc_wait(rdc_config_t *uparms, spcs_s_info_t kstatus) 4916 { 4917 rdc_k_info_t *krdc; 4918 rdc_u_info_t *urdc; 4919 int index; 4920 int need_check = 0; 4921 4922 mutex_enter(&rdc_conf_lock); 4923 index = rdc_lookup_byname(uparms->rdc_set); 4924 if (index >= 0) 4925 krdc = &rdc_k_info[index]; 4926 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 4927 mutex_exit(&rdc_conf_lock); 4928 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 4929 uparms->rdc_set->secondary.file); 4930 return (RDC_EALREADY); 4931 } 4932 4933 urdc = &rdc_u_info[index]; 4934 if (!(rdc_get_vflags(urdc) & RDC_PRIMARY)) { 4935 mutex_exit(&rdc_conf_lock); 4936 return (0); 4937 } 4938 4939 set_busy(krdc); 4940 if (krdc->type_flag == 0) { 4941 /* A resume or enable failed */ 4942 wakeup_busy(krdc); 4943 mutex_exit(&rdc_conf_lock); 4944 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 4945 uparms->rdc_set->secondary.file); 4946 return (RDC_EALREADY); 4947 } 4948 mutex_exit(&rdc_conf_lock); 4949 4950 rdc_group_enter(krdc); 4951 if (rdc_check(krdc, uparms->rdc_set)) { 4952 rdc_group_exit(krdc); 4953 mutex_enter(&rdc_conf_lock); 4954 wakeup_busy(krdc); 4955 mutex_exit(&rdc_conf_lock); 4956 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 4957 uparms->rdc_set->secondary.file); 4958 return (RDC_EALREADY); 4959 } 4960 4961 if ((rdc_get_vflags(urdc) & (RDC_SYNCING | RDC_PRIMARY)) != 4962 (RDC_SYNCING | RDC_PRIMARY)) { 4963 rdc_group_exit(krdc); 4964 mutex_enter(&rdc_conf_lock); 4965 wakeup_busy(krdc); 4966 mutex_exit(&rdc_conf_lock); 4967 return (0); 4968 } 4969 if (rdc_get_vflags(urdc) & RDC_SYNCING) { 4970 need_check = 1; 4971 } 4972 rdc_group_exit(krdc); 4973 4974 mutex_enter(&net_blk_lock); 4975 4976 mutex_enter(&rdc_conf_lock); 4977 wakeup_busy(krdc); 4978 mutex_exit(&rdc_conf_lock); 4979 4980 (void) cv_wait_sig(&krdc->synccv, &net_blk_lock); 4981 4982 mutex_exit(&net_blk_lock); 4983 if (need_check) { 4984 if (krdc->sync_done == RDC_COMPLETED) { 4985 return (0); 4986 } else if (krdc->sync_done == RDC_FAILED) { 4987 return (EIO); 4988 } 4989 } 4990 return (0); 4991 } 4992 4993 4994 static int 4995 rdc_health(rdc_config_t *uparms, spcs_s_info_t kstatus, int *rvp) 4996 { 4997 rdc_k_info_t *krdc; 4998 rdc_u_info_t *urdc; 4999 int rc = 0; 5000 int index; 5001 5002 mutex_enter(&rdc_conf_lock); 5003 index = rdc_lookup_byname(uparms->rdc_set); 5004 if (index >= 0) 5005 krdc = &rdc_k_info[index]; 5006 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 5007 mutex_exit(&rdc_conf_lock); 5008 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5009 uparms->rdc_set->secondary.file); 5010 return (RDC_EALREADY); 5011 } 5012 5013 set_busy(krdc); 5014 if (krdc->type_flag == 0) { 5015 /* A resume or enable failed */ 5016 wakeup_busy(krdc); 5017 mutex_exit(&rdc_conf_lock); 5018 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5019 uparms->rdc_set->secondary.file); 5020 return (RDC_EALREADY); 5021 } 5022 5023 mutex_exit(&rdc_conf_lock); 5024 5025 rdc_group_enter(krdc); 5026 if (rdc_check(krdc, uparms->rdc_set)) { 5027 rdc_group_exit(krdc); 5028 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5029 uparms->rdc_set->secondary.file); 5030 rc = RDC_EALREADY; 5031 goto done; 5032 } 5033 5034 urdc = &rdc_u_info[index]; 5035 if (rdc_isactive_if(&(urdc->primary.addr), &(urdc->secondary.addr))) 5036 *rvp = RDC_ACTIVE; 5037 else 5038 *rvp = RDC_INACTIVE; 5039 5040 rdc_group_exit(krdc); 5041 5042 done: 5043 mutex_enter(&rdc_conf_lock); 5044 wakeup_busy(krdc); 5045 mutex_exit(&rdc_conf_lock); 5046 5047 return (rc); 5048 } 5049 5050 5051 static int 5052 rdc_reconfig(rdc_config_t *uparms, spcs_s_info_t kstatus) 5053 { 5054 rdc_k_info_t *krdc; 5055 rdc_u_info_t *urdc; 5056 int rc = -2; 5057 int index; 5058 5059 mutex_enter(&rdc_conf_lock); 5060 index = rdc_lookup_byname(uparms->rdc_set); 5061 if (index >= 0) 5062 krdc = &rdc_k_info[index]; 5063 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 5064 mutex_exit(&rdc_conf_lock); 5065 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5066 uparms->rdc_set->secondary.file); 5067 return (RDC_EALREADY); 5068 } 5069 5070 urdc = &rdc_u_info[index]; 5071 set_busy(krdc); 5072 if (krdc->type_flag == 0) { 5073 /* A resume or enable failed */ 5074 wakeup_busy(krdc); 5075 mutex_exit(&rdc_conf_lock); 5076 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5077 uparms->rdc_set->secondary.file); 5078 return (RDC_EALREADY); 5079 } 5080 5081 mutex_exit(&rdc_conf_lock); 5082 5083 rdc_group_enter(krdc); 5084 if (rdc_check(krdc, uparms->rdc_set)) { 5085 rdc_group_exit(krdc); 5086 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5087 uparms->rdc_set->secondary.file); 5088 rc = RDC_EALREADY; 5089 goto done; 5090 } 5091 if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd)) 5092 (void) rdc_reset_bitmap(krdc); 5093 5094 /* Move to a new bitmap if necessary */ 5095 if (strncmp(urdc->primary.bitmap, uparms->rdc_set->primary.bitmap, 5096 NSC_MAXPATH) != 0) { 5097 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 5098 rc = rdc_move_bitmap(krdc, 5099 uparms->rdc_set->primary.bitmap); 5100 } else { 5101 (void) strncpy(urdc->primary.bitmap, 5102 uparms->rdc_set->primary.bitmap, NSC_MAXPATH); 5103 /* simulate a succesful rdc_move_bitmap */ 5104 rc = 0; 5105 } 5106 } 5107 if (strncmp(urdc->secondary.bitmap, uparms->rdc_set->secondary.bitmap, 5108 NSC_MAXPATH) != 0) { 5109 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 5110 (void) strncpy(urdc->secondary.bitmap, 5111 uparms->rdc_set->secondary.bitmap, NSC_MAXPATH); 5112 /* simulate a succesful rdc_move_bitmap */ 5113 rc = 0; 5114 } else { 5115 rc = rdc_move_bitmap(krdc, 5116 uparms->rdc_set->secondary.bitmap); 5117 } 5118 } 5119 if (rc == -1) { 5120 rdc_group_exit(krdc); 5121 spcs_s_add(kstatus, RDC_EBMPRECONFIG, 5122 uparms->rdc_set->secondary.intf, 5123 uparms->rdc_set->secondary.file); 5124 rc = RDC_EBMPRECONFIG; 5125 goto done; 5126 } 5127 5128 /* 5129 * At this point we fail any other type of reconfig 5130 * if not in logging mode and we did not do a bitmap reconfig 5131 */ 5132 5133 if (!(rdc_get_vflags(urdc) & RDC_LOGGING) && rc == -2) { 5134 /* no other changes possible unless logging */ 5135 rdc_group_exit(krdc); 5136 spcs_s_add(kstatus, RDC_ENOTLOGGING, 5137 uparms->rdc_set->primary.intf, 5138 uparms->rdc_set->primary.file, 5139 uparms->rdc_set->secondary.intf, 5140 uparms->rdc_set->secondary.file); 5141 rc = RDC_ENOTLOGGING; 5142 goto done; 5143 } 5144 rc = 0; 5145 /* Change direct file if necessary */ 5146 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && 5147 strncmp(urdc->direct_file, uparms->rdc_set->direct_file, 5148 NSC_MAXPATH)) { 5149 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) { 5150 rdc_group_exit(krdc); 5151 goto notlogging; 5152 } 5153 rdc_close_direct(krdc); 5154 (void) strncpy(urdc->direct_file, uparms->rdc_set->direct_file, 5155 NSC_MAXPATH); 5156 5157 if (urdc->direct_file[0]) { 5158 if (rdc_open_direct(krdc) == NULL) 5159 rdc_set_flags(urdc, RDC_FCAL_FAILED); 5160 else 5161 rdc_clr_flags(urdc, RDC_FCAL_FAILED); 5162 } 5163 } 5164 5165 rdc_group_exit(krdc); 5166 5167 /* Change group if necessary */ 5168 if (strncmp(urdc->group_name, uparms->rdc_set->group_name, 5169 NSC_MAXPATH) != 0) { 5170 char orig_group[NSC_MAXPATH]; 5171 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) 5172 goto notlogging; 5173 mutex_enter(&rdc_conf_lock); 5174 5175 (void) strncpy(orig_group, urdc->group_name, NSC_MAXPATH); 5176 (void) strncpy(urdc->group_name, uparms->rdc_set->group_name, 5177 NSC_MAXPATH); 5178 5179 rc = change_group(krdc, uparms->options); 5180 if (rc == RDC_EQNOADD) { 5181 mutex_exit(&rdc_conf_lock); 5182 spcs_s_add(kstatus, RDC_EQNOADD, 5183 uparms->rdc_set->disk_queue); 5184 goto done; 5185 } else if (rc < 0) { 5186 (void) strncpy(urdc->group_name, orig_group, 5187 NSC_MAXPATH); 5188 mutex_exit(&rdc_conf_lock); 5189 spcs_s_add(kstatus, RDC_EGROUP, 5190 urdc->primary.intf, urdc->primary.file, 5191 urdc->secondary.intf, urdc->secondary.file, 5192 uparms->rdc_set->group_name); 5193 rc = RDC_EGROUP; 5194 goto done; 5195 } 5196 5197 mutex_exit(&rdc_conf_lock); 5198 5199 if (rc >= 0) { 5200 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) 5201 goto notlogging; 5202 if (uparms->options & RDC_OPT_ASYNC) { 5203 mutex_enter(&rdc_conf_lock); 5204 krdc->type_flag |= RDC_ASYNCMODE; 5205 mutex_exit(&rdc_conf_lock); 5206 if (uparms->options & RDC_OPT_PRIMARY) 5207 krdc->bitmap_ref = 5208 (uchar_t *)kmem_zalloc( 5209 (krdc->bitmap_size * BITS_IN_BYTE * 5210 BMAP_REF_PREF_SIZE), KM_SLEEP); 5211 rdc_group_enter(krdc); 5212 rdc_set_flags(urdc, RDC_ASYNC); 5213 rdc_group_exit(krdc); 5214 } else { 5215 mutex_enter(&rdc_conf_lock); 5216 krdc->type_flag &= ~RDC_ASYNCMODE; 5217 mutex_exit(&rdc_conf_lock); 5218 rdc_group_enter(krdc); 5219 rdc_clr_flags(urdc, RDC_ASYNC); 5220 rdc_group_exit(krdc); 5221 if (krdc->bitmap_ref) { 5222 kmem_free(krdc->bitmap_ref, 5223 (krdc->bitmap_size * BITS_IN_BYTE * 5224 BMAP_REF_PREF_SIZE)); 5225 krdc->bitmap_ref = NULL; 5226 } 5227 } 5228 } 5229 } else { 5230 if ((((uparms->options & RDC_OPT_ASYNC) == 0) && 5231 ((krdc->type_flag & RDC_ASYNCMODE) != 0)) || 5232 (((uparms->options & RDC_OPT_ASYNC) != 0) && 5233 ((krdc->type_flag & RDC_ASYNCMODE) == 0))) { 5234 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) 5235 goto notlogging; 5236 5237 if (krdc->group->count > 1) { 5238 spcs_s_add(kstatus, RDC_EGROUPMODE); 5239 rc = RDC_EGROUPMODE; 5240 goto done; 5241 } 5242 } 5243 5244 /* Switch sync/async if necessary */ 5245 if (krdc->group->count == 1) { 5246 /* Only member of group. Can change sync/async */ 5247 if (((uparms->options & RDC_OPT_ASYNC) == 0) && 5248 ((krdc->type_flag & RDC_ASYNCMODE) != 0)) { 5249 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) 5250 goto notlogging; 5251 /* switch to sync */ 5252 mutex_enter(&rdc_conf_lock); 5253 krdc->type_flag &= ~RDC_ASYNCMODE; 5254 if (RDC_IS_DISKQ(krdc->group)) { 5255 krdc->group->flags &= ~RDC_DISKQUE; 5256 krdc->group->flags |= RDC_MEMQUE; 5257 rdc_unintercept_diskq(krdc->group); 5258 mutex_enter(&krdc->group->diskqmutex); 5259 rdc_close_diskq(krdc->group); 5260 mutex_exit(&krdc->group->diskqmutex); 5261 bzero(&urdc->disk_queue, 5262 sizeof (urdc->disk_queue)); 5263 } 5264 mutex_exit(&rdc_conf_lock); 5265 rdc_group_enter(krdc); 5266 rdc_clr_flags(urdc, RDC_ASYNC); 5267 rdc_group_exit(krdc); 5268 if (krdc->bitmap_ref) { 5269 kmem_free(krdc->bitmap_ref, 5270 (krdc->bitmap_size * BITS_IN_BYTE * 5271 BMAP_REF_PREF_SIZE)); 5272 krdc->bitmap_ref = NULL; 5273 } 5274 } else if (((uparms->options & RDC_OPT_ASYNC) != 0) && 5275 ((krdc->type_flag & RDC_ASYNCMODE) == 0)) { 5276 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) 5277 goto notlogging; 5278 /* switch to async */ 5279 mutex_enter(&rdc_conf_lock); 5280 krdc->type_flag |= RDC_ASYNCMODE; 5281 mutex_exit(&rdc_conf_lock); 5282 if (uparms->options & RDC_OPT_PRIMARY) 5283 krdc->bitmap_ref = 5284 (uchar_t *)kmem_zalloc( 5285 (krdc->bitmap_size * BITS_IN_BYTE * 5286 BMAP_REF_PREF_SIZE), KM_SLEEP); 5287 rdc_group_enter(krdc); 5288 rdc_set_flags(urdc, RDC_ASYNC); 5289 rdc_group_exit(krdc); 5290 } 5291 } 5292 } 5293 /* Reverse concept of primary and secondary */ 5294 if ((uparms->options & RDC_OPT_REVERSE_ROLE) != 0) { 5295 rdc_set_t rdc_set; 5296 struct netbuf paddr, saddr; 5297 5298 mutex_enter(&rdc_conf_lock); 5299 5300 /* 5301 * Disallow role reversal for advanced configurations 5302 */ 5303 5304 if (IS_MANY(krdc) || IS_MULTI(krdc)) { 5305 mutex_exit(&rdc_conf_lock); 5306 spcs_s_add(kstatus, RDC_EMASTER, urdc->primary.intf, 5307 urdc->primary.file, urdc->secondary.intf, 5308 urdc->secondary.file); 5309 return (RDC_EMASTER); 5310 } 5311 bzero((void *) &rdc_set, sizeof (rdc_set_t)); 5312 dup_rdc_netbuf(&urdc->primary.addr, &saddr); 5313 dup_rdc_netbuf(&urdc->secondary.addr, &paddr); 5314 free_rdc_netbuf(&urdc->primary.addr); 5315 free_rdc_netbuf(&urdc->secondary.addr); 5316 dup_rdc_netbuf(&saddr, &urdc->secondary.addr); 5317 dup_rdc_netbuf(&paddr, &urdc->primary.addr); 5318 free_rdc_netbuf(&paddr); 5319 free_rdc_netbuf(&saddr); 5320 /* copy primary parts of urdc to rdc_set field by field */ 5321 (void) strncpy(rdc_set.primary.intf, urdc->primary.intf, 5322 MAX_RDC_HOST_SIZE); 5323 (void) strncpy(rdc_set.primary.file, urdc->primary.file, 5324 NSC_MAXPATH); 5325 (void) strncpy(rdc_set.primary.bitmap, urdc->primary.bitmap, 5326 NSC_MAXPATH); 5327 5328 /* Now overwrite urdc primary */ 5329 (void) strncpy(urdc->primary.intf, urdc->secondary.intf, 5330 MAX_RDC_HOST_SIZE); 5331 (void) strncpy(urdc->primary.file, urdc->secondary.file, 5332 NSC_MAXPATH); 5333 (void) strncpy(urdc->primary.bitmap, urdc->secondary.bitmap, 5334 NSC_MAXPATH); 5335 5336 /* Now ovwewrite urdc secondary */ 5337 (void) strncpy(urdc->secondary.intf, rdc_set.primary.intf, 5338 MAX_RDC_HOST_SIZE); 5339 (void) strncpy(urdc->secondary.file, rdc_set.primary.file, 5340 NSC_MAXPATH); 5341 (void) strncpy(urdc->secondary.bitmap, rdc_set.primary.bitmap, 5342 NSC_MAXPATH); 5343 5344 if (rdc_get_vflags(urdc) & RDC_PRIMARY) { 5345 rdc_clr_flags(urdc, RDC_PRIMARY); 5346 if (krdc->intf) { 5347 krdc->intf->issecondary = 1; 5348 krdc->intf->isprimary = 0; 5349 krdc->intf->if_down = 1; 5350 } 5351 } else { 5352 rdc_set_flags(urdc, RDC_PRIMARY); 5353 if (krdc->intf) { 5354 krdc->intf->issecondary = 0; 5355 krdc->intf->isprimary = 1; 5356 krdc->intf->if_down = 1; 5357 } 5358 } 5359 5360 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && 5361 ((krdc->type_flag & RDC_ASYNCMODE) != 0)) { 5362 if (!krdc->bitmap_ref) 5363 krdc->bitmap_ref = 5364 (uchar_t *)kmem_zalloc((krdc->bitmap_size * 5365 BITS_IN_BYTE * BMAP_REF_PREF_SIZE), 5366 KM_SLEEP); 5367 if (krdc->bitmap_ref == NULL) { 5368 cmn_err(CE_WARN, 5369 "!rdc_reconfig: bitmap_ref alloc %" 5370 NSC_SZFMT " failed", 5371 krdc->bitmap_size * BITS_IN_BYTE * 5372 BMAP_REF_PREF_SIZE); 5373 mutex_exit(&rdc_conf_lock); 5374 return (-1); 5375 } 5376 } 5377 5378 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && 5379 (rdc_get_vflags(urdc) & RDC_SYNC_NEEDED)) { 5380 /* Primary, so reverse sync needed */ 5381 rdc_many_enter(krdc); 5382 rdc_clr_flags(urdc, RDC_SYNC_NEEDED); 5383 rdc_set_mflags(urdc, RDC_RSYNC_NEEDED); 5384 rdc_many_exit(krdc); 5385 } else if (rdc_get_vflags(urdc) & RDC_RSYNC_NEEDED) { 5386 /* Secondary, so forward sync needed */ 5387 rdc_many_enter(krdc); 5388 rdc_clr_flags(urdc, RDC_RSYNC_NEEDED); 5389 rdc_set_flags(urdc, RDC_SYNC_NEEDED); 5390 rdc_many_exit(krdc); 5391 } 5392 5393 /* 5394 * rewrite bitmap header 5395 */ 5396 rdc_write_state(urdc); 5397 mutex_exit(&rdc_conf_lock); 5398 } 5399 5400 done: 5401 mutex_enter(&rdc_conf_lock); 5402 wakeup_busy(krdc); 5403 mutex_exit(&rdc_conf_lock); 5404 5405 return (rc); 5406 5407 notlogging: 5408 /* no other changes possible unless logging */ 5409 mutex_enter(&rdc_conf_lock); 5410 wakeup_busy(krdc); 5411 mutex_exit(&rdc_conf_lock); 5412 spcs_s_add(kstatus, RDC_ENOTLOGGING, urdc->primary.intf, 5413 urdc->primary.file, urdc->secondary.intf, 5414 urdc->secondary.file); 5415 return (RDC_ENOTLOGGING); 5416 } 5417 5418 static int 5419 rdc_reset(rdc_config_t *uparms, spcs_s_info_t kstatus) 5420 { 5421 rdc_k_info_t *krdc; 5422 rdc_u_info_t *urdc; 5423 int rc = 0; 5424 int index; 5425 int cleared_error = 0; 5426 5427 mutex_enter(&rdc_conf_lock); 5428 index = rdc_lookup_byname(uparms->rdc_set); 5429 if (index >= 0) 5430 krdc = &rdc_k_info[index]; 5431 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 5432 mutex_exit(&rdc_conf_lock); 5433 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5434 uparms->rdc_set->secondary.file); 5435 return (RDC_EALREADY); 5436 } 5437 5438 urdc = &rdc_u_info[index]; 5439 set_busy(krdc); 5440 if (krdc->type_flag == 0) { 5441 /* A resume or enable failed */ 5442 wakeup_busy(krdc); 5443 mutex_exit(&rdc_conf_lock); 5444 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5445 uparms->rdc_set->secondary.file); 5446 return (RDC_EALREADY); 5447 } 5448 5449 mutex_exit(&rdc_conf_lock); 5450 5451 rdc_group_enter(krdc); 5452 if (rdc_check(krdc, uparms->rdc_set)) { 5453 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5454 uparms->rdc_set->secondary.file); 5455 rc = RDC_EALREADY; 5456 goto done; 5457 } 5458 5459 if ((rdc_get_vflags(urdc) & RDC_BMP_FAILED) && (krdc->bitmapfd)) { 5460 if (rdc_reset_bitmap(krdc) == 0) 5461 cleared_error++; 5462 } 5463 5464 /* Fix direct file if necessary */ 5465 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && urdc->direct_file[0]) { 5466 if (rdc_open_direct(krdc) == NULL) 5467 rdc_set_flags(urdc, RDC_FCAL_FAILED); 5468 else { 5469 rdc_clr_flags(urdc, RDC_FCAL_FAILED); 5470 cleared_error++; 5471 } 5472 } 5473 5474 if ((rdc_get_vflags(urdc) & RDC_VOL_FAILED)) { 5475 rdc_many_enter(krdc); 5476 rdc_clr_flags(urdc, RDC_VOL_FAILED); 5477 cleared_error++; 5478 rdc_many_exit(krdc); 5479 } 5480 5481 if (cleared_error) { 5482 /* cleared an error so we should be in logging mode */ 5483 rdc_set_flags_log(urdc, RDC_LOGGING, "set reset"); 5484 } 5485 rdc_group_exit(krdc); 5486 5487 if ((rdc_get_vflags(urdc) & RDC_DISKQ_FAILED)) 5488 rdc_unfail_diskq(krdc); 5489 5490 done: 5491 mutex_enter(&rdc_conf_lock); 5492 wakeup_busy(krdc); 5493 mutex_exit(&rdc_conf_lock); 5494 5495 return (rc); 5496 } 5497 5498 5499 static int 5500 rdc_tunable(rdc_config_t *uparms, spcs_s_info_t kstatus) 5501 { 5502 rdc_k_info_t *krdc; 5503 rdc_u_info_t *urdc; 5504 rdc_k_info_t *p; 5505 rdc_u_info_t *q; 5506 int rc = 0; 5507 int index; 5508 5509 mutex_enter(&rdc_conf_lock); 5510 index = rdc_lookup_byname(uparms->rdc_set); 5511 if (index >= 0) 5512 krdc = &rdc_k_info[index]; 5513 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 5514 mutex_exit(&rdc_conf_lock); 5515 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5516 uparms->rdc_set->secondary.file); 5517 return (RDC_EALREADY); 5518 } 5519 5520 urdc = &rdc_u_info[index]; 5521 set_busy(krdc); 5522 if (krdc->type_flag == 0) { 5523 /* A resume or enable failed */ 5524 wakeup_busy(krdc); 5525 mutex_exit(&rdc_conf_lock); 5526 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5527 uparms->rdc_set->secondary.file); 5528 return (RDC_EALREADY); 5529 } 5530 5531 mutex_exit(&rdc_conf_lock); 5532 5533 rdc_group_enter(krdc); 5534 if (rdc_check(krdc, uparms->rdc_set)) { 5535 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5536 uparms->rdc_set->secondary.file); 5537 rc = RDC_EALREADY; 5538 goto done; 5539 } 5540 5541 if (uparms->rdc_set->maxqfbas > 0) { 5542 urdc->maxqfbas = uparms->rdc_set->maxqfbas; 5543 rdc_write_state(urdc); 5544 for (p = krdc->group_next; p != krdc; p = p->group_next) { 5545 q = &rdc_u_info[p->index]; 5546 q->maxqfbas = urdc->maxqfbas; 5547 rdc_write_state(q); 5548 } 5549 } 5550 5551 if (uparms->rdc_set->maxqitems > 0) { 5552 urdc->maxqitems = uparms->rdc_set->maxqitems; 5553 rdc_write_state(urdc); 5554 for (p = krdc->group_next; p != krdc; p = p->group_next) { 5555 q = &rdc_u_info[p->index]; 5556 q->maxqitems = urdc->maxqitems; 5557 rdc_write_state(q); 5558 } 5559 } 5560 5561 if (uparms->options & RDC_OPT_SET_QNOBLOCK) { 5562 disk_queue *que; 5563 5564 if (!RDC_IS_DISKQ(krdc->group)) { 5565 spcs_s_add(kstatus, RDC_EQNOQUEUE, urdc->primary.intf, 5566 urdc->primary.file, urdc->secondary.intf, 5567 urdc->secondary.file); 5568 rc = RDC_EQNOQUEUE; 5569 goto done; 5570 } 5571 5572 que = &krdc->group->diskq; 5573 mutex_enter(QLOCK(que)); 5574 SET_QSTATE(que, RDC_QNOBLOCK); 5575 /* queue will fail if this fails */ 5576 (void) rdc_stamp_diskq(krdc, 0, RDC_GROUP_LOCKED); 5577 mutex_exit(QLOCK(que)); 5578 5579 } 5580 5581 if (uparms->options & RDC_OPT_CLR_QNOBLOCK) { 5582 disk_queue *que; 5583 5584 if (!RDC_IS_DISKQ(krdc->group)) { 5585 spcs_s_add(kstatus, RDC_EQNOQUEUE, urdc->primary.intf, 5586 urdc->primary.file, urdc->secondary.intf, 5587 urdc->secondary.file); 5588 rc = RDC_EQNOQUEUE; 5589 goto done; 5590 } 5591 que = &krdc->group->diskq; 5592 mutex_enter(QLOCK(que)); 5593 CLR_QSTATE(que, RDC_QNOBLOCK); 5594 /* queue will fail if this fails */ 5595 (void) rdc_stamp_diskq(krdc, 0, RDC_GROUP_LOCKED); 5596 mutex_exit(QLOCK(que)); 5597 5598 } 5599 if (uparms->rdc_set->asyncthr > 0) { 5600 urdc->asyncthr = uparms->rdc_set->asyncthr; 5601 rdc_write_state(urdc); 5602 for (p = krdc->group_next; p != krdc; p = p->group_next) { 5603 q = &rdc_u_info[p->index]; 5604 q->asyncthr = urdc->asyncthr; 5605 rdc_write_state(q); 5606 } 5607 } 5608 5609 if (uparms->rdc_set->autosync >= 0) { 5610 if (uparms->rdc_set->autosync == 0) 5611 urdc->autosync = 0; 5612 else 5613 urdc->autosync = 1; 5614 5615 rdc_write_state(urdc); 5616 5617 /* Changed autosync, so update rest of the group */ 5618 5619 for (p = krdc->group_next; p != krdc; p = p->group_next) { 5620 q = &rdc_u_info[p->index]; 5621 q->autosync = urdc->autosync; 5622 rdc_write_state(q); 5623 } 5624 } 5625 5626 done: 5627 rdc_group_exit(krdc); 5628 5629 mutex_enter(&rdc_conf_lock); 5630 wakeup_busy(krdc); 5631 mutex_exit(&rdc_conf_lock); 5632 5633 return (rc); 5634 } 5635 5636 /* 5637 * Yet another standard thing that is not standard ... 5638 */ 5639 #ifndef offsetof 5640 #define offsetof(s, m) ((size_t)(&((s *)0)->m)) 5641 #endif 5642 5643 static int 5644 rdc_status(void *arg, int mode, rdc_config_t *uparms, spcs_s_info_t kstatus) 5645 { 5646 rdc_k_info_t *krdc; 5647 rdc_u_info_t *urdc; 5648 disk_queue *dqp; 5649 int rc = 0; 5650 int index; 5651 char *ptr; 5652 extern int rdc_status_copy32(const void *, void *, size_t, int); 5653 5654 mutex_enter(&rdc_conf_lock); 5655 index = rdc_lookup_byname(uparms->rdc_set); 5656 if (index >= 0) 5657 krdc = &rdc_k_info[index]; 5658 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 5659 mutex_exit(&rdc_conf_lock); 5660 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5661 uparms->rdc_set->secondary.file); 5662 return (RDC_EALREADY); 5663 } 5664 5665 set_busy(krdc); 5666 if (krdc->type_flag == 0) { 5667 /* A resume or enable failed */ 5668 wakeup_busy(krdc); 5669 mutex_exit(&rdc_conf_lock); 5670 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5671 uparms->rdc_set->secondary.file); 5672 return (RDC_EALREADY); 5673 } 5674 5675 mutex_exit(&rdc_conf_lock); 5676 5677 rdc_group_enter(krdc); 5678 if (rdc_check(krdc, uparms->rdc_set)) { 5679 rdc_group_exit(krdc); 5680 spcs_s_add(kstatus, RDC_EALREADY, uparms->rdc_set->primary.file, 5681 uparms->rdc_set->secondary.file); 5682 rc = RDC_EALREADY; 5683 goto done; 5684 } 5685 5686 urdc = &rdc_u_info[index]; 5687 5688 /* 5689 * sneak out qstate in urdc->flags 5690 * this is harmless because it's value is not used 5691 * in urdc->flags. the real qstate is kept in 5692 * group->diskq->disk_hdr.h.state 5693 */ 5694 if (RDC_IS_DISKQ(krdc->group)) { 5695 dqp = &krdc->group->diskq; 5696 if (IS_QSTATE(dqp, RDC_QNOBLOCK)) 5697 urdc->flags |= RDC_QNOBLOCK; 5698 } 5699 5700 if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 5701 ptr = (char *)arg + offsetof(struct rdc_config32, rdc_set); 5702 rc = rdc_status_copy32(urdc, ptr, sizeof (struct rdc_set32), 5703 mode); 5704 } else { 5705 ptr = (char *)arg + offsetof(struct rdc_config, rdc_set); 5706 rc = ddi_copyout(urdc, ptr, sizeof (struct rdc_set), mode); 5707 } 5708 /* clear out qstate from flags */ 5709 urdc->flags &= ~RDC_QNOBLOCK; 5710 5711 if (rc) 5712 rc = EFAULT; 5713 5714 rdc_group_exit(krdc); 5715 done: 5716 mutex_enter(&rdc_conf_lock); 5717 wakeup_busy(krdc); 5718 mutex_exit(&rdc_conf_lock); 5719 5720 return (rc); 5721 } 5722 5723 /* 5724 * Overwrite the bitmap with one supplied by the 5725 * user. 5726 * Copy into all bitmaps that are tracking this volume. 5727 */ 5728 5729 int 5730 rdc_bitmapset(int op, char *sechost, char *secdev, void *bmapaddr, int bmapsz, 5731 nsc_off_t off, int mode) 5732 { 5733 int rc; 5734 rdc_k_info_t *krdc; 5735 int *indexvec; 5736 int index; 5737 int indexit; 5738 kmutex_t **grouplocks; 5739 int i; 5740 int groupind; 5741 5742 if (off % FBA_SIZE(1)) { 5743 /* Must be modulo FBA */ 5744 cmn_err(CE_WARN, "!bitmapset: Offset is not on an FBA " 5745 "boundary %llu", (unsigned long long)off); 5746 return (EINVAL); 5747 } 5748 if (bmapsz % FBA_SIZE(1)) { 5749 /* Must be modulo FBA */ 5750 cmn_err(CE_WARN, "!bitmapset: Size is not on an FBA " 5751 "boundary %d", bmapsz); 5752 return (EINVAL); 5753 } 5754 5755 mutex_enter(&rdc_conf_lock); 5756 index = rdc_lookup_byhostdev(sechost, secdev); 5757 if (index >= 0) { 5758 krdc = &rdc_k_info[index]; 5759 } 5760 if (index < 0 || (krdc->type_flag & RDC_DISABLEPEND)) { 5761 rc = ENODEV; 5762 mutex_exit(&rdc_conf_lock); 5763 return (rc); 5764 } 5765 indexvec = kmem_alloc(rdc_max_sets * sizeof (int), KM_SLEEP); 5766 grouplocks = kmem_alloc(rdc_max_sets * sizeof (kmutex_t *), KM_SLEEP); 5767 5768 /* 5769 * I now have this set, and I want to take the group 5770 * lock on it, and all the group locks of all the 5771 * sets on the many and multi-hop links. 5772 * I have to take the many lock while traversing the 5773 * many/multi links. 5774 * I think I also need to set the busy count on this 5775 * set, otherwise when I drop the conf_lock, what 5776 * will stop some other process from coming in and 5777 * issuing a disable? 5778 */ 5779 set_busy(krdc); 5780 mutex_exit(&rdc_conf_lock); 5781 5782 retrylock: 5783 groupind = 0; 5784 indexit = 0; 5785 rdc_many_enter(krdc); 5786 /* 5787 * Take this initial sets group lock first. 5788 */ 5789 if (!mutex_tryenter(&krdc->group->lock)) { 5790 rdc_many_exit(krdc); 5791 goto retrylock; 5792 } 5793 5794 grouplocks[groupind] = &krdc->group->lock; 5795 groupind++; 5796 5797 rc = rdc_checkforbitmap(index, off + bmapsz); 5798 if (rc) { 5799 goto done; 5800 } 5801 indexvec[indexit] = index; 5802 indexit++; 5803 if (IS_MANY(krdc)) { 5804 rdc_k_info_t *ktmp; 5805 5806 for (ktmp = krdc->many_next; ktmp != krdc; 5807 ktmp = ktmp->many_next) { 5808 /* 5809 * attempt to take the group lock, 5810 * if we don't already have it. 5811 */ 5812 if (ktmp->group == NULL) { 5813 rc = ENODEV; 5814 goto done; 5815 } 5816 for (i = 0; i < groupind; i++) { 5817 if (grouplocks[i] == &ktmp->group->lock) 5818 /* already have the group lock */ 5819 break; 5820 } 5821 /* 5822 * didn't find our lock in our collection, 5823 * attempt to take group lock. 5824 */ 5825 if (i >= groupind) { 5826 if (!mutex_tryenter(&ktmp->group->lock)) { 5827 for (i = 0; i < groupind; i++) { 5828 mutex_exit(grouplocks[i]); 5829 } 5830 rdc_many_exit(krdc); 5831 goto retrylock; 5832 } 5833 grouplocks[groupind] = &ktmp->group->lock; 5834 groupind++; 5835 } 5836 rc = rdc_checkforbitmap(ktmp->index, off + bmapsz); 5837 if (rc == 0) { 5838 indexvec[indexit] = ktmp->index; 5839 indexit++; 5840 } else { 5841 goto done; 5842 } 5843 } 5844 } 5845 if (IS_MULTI(krdc)) { 5846 rdc_k_info_t *kmulti = krdc->multi_next; 5847 5848 if (kmulti->group == NULL) { 5849 rc = ENODEV; 5850 goto done; 5851 } 5852 /* 5853 * This can't be in our group already. 5854 */ 5855 if (!mutex_tryenter(&kmulti->group->lock)) { 5856 for (i = 0; i < groupind; i++) { 5857 mutex_exit(grouplocks[i]); 5858 } 5859 rdc_many_exit(krdc); 5860 goto retrylock; 5861 } 5862 grouplocks[groupind] = &kmulti->group->lock; 5863 groupind++; 5864 5865 rc = rdc_checkforbitmap(kmulti->index, off + bmapsz); 5866 if (rc == 0) { 5867 indexvec[indexit] = kmulti->index; 5868 indexit++; 5869 } else { 5870 goto done; 5871 } 5872 } 5873 rc = rdc_installbitmap(op, bmapaddr, bmapsz, off, mode, indexvec, 5874 indexit); 5875 done: 5876 for (i = 0; i < groupind; i++) { 5877 mutex_exit(grouplocks[i]); 5878 } 5879 rdc_many_exit(krdc); 5880 mutex_enter(&rdc_conf_lock); 5881 wakeup_busy(krdc); 5882 mutex_exit(&rdc_conf_lock); 5883 kmem_free(indexvec, rdc_max_sets * sizeof (int)); 5884 kmem_free(grouplocks, rdc_max_sets * sizeof (kmutex_t *)); 5885 return (rc); 5886 } 5887 5888 static int 5889 rdc_checkforbitmap(int index, nsc_off_t limit) 5890 { 5891 rdc_k_info_t *krdc; 5892 rdc_u_info_t *urdc; 5893 5894 krdc = &rdc_k_info[index]; 5895 urdc = &rdc_u_info[index]; 5896 5897 if (!IS_ENABLED(urdc)) { 5898 return (EIO); 5899 } 5900 if (!(rdc_get_vflags(urdc) & RDC_LOGGING)) { 5901 return (ENXIO); 5902 } 5903 if (krdc->dcio_bitmap == NULL) { 5904 cmn_err(CE_WARN, "!checkforbitmap: No bitmap for set (%s:%s)", 5905 urdc->secondary.intf, urdc->secondary.file); 5906 return (ENOENT); 5907 } 5908 if (limit > krdc->bitmap_size) { 5909 cmn_err(CE_WARN, "!checkbitmap: Bitmap exceeded, " 5910 "incore %" NSC_SZFMT " user supplied %" NSC_SZFMT 5911 " for set (%s:%s)", krdc->bitmap_size, 5912 limit, urdc->secondary.intf, urdc->secondary.file); 5913 return (ENOSPC); 5914 } 5915 return (0); 5916 } 5917 5918 5919 5920 /* 5921 * Copy the user supplied bitmap to this set. 5922 */ 5923 static int 5924 rdc_installbitmap(int op, void *bmapaddr, int bmapsz, 5925 nsc_off_t off, int mode, int *vec, int veccnt) 5926 { 5927 int rc; 5928 nsc_off_t sfba; 5929 nsc_off_t efba; 5930 nsc_off_t fba; 5931 void *ormem = NULL; 5932 int len; 5933 int left; 5934 int copied; 5935 int index; 5936 rdc_k_info_t *krdc; 5937 rdc_u_info_t *urdc; 5938 5939 rc = 0; 5940 ormem = kmem_alloc(RDC_MAXDATA, KM_SLEEP); 5941 left = bmapsz; 5942 copied = 0; 5943 while (left > 0) { 5944 if (left > RDC_MAXDATA) { 5945 len = RDC_MAXDATA; 5946 } else { 5947 len = left; 5948 } 5949 if (ddi_copyin((char *)bmapaddr + copied, ormem, 5950 len, mode)) { 5951 cmn_err(CE_WARN, "!installbitmap: Copyin failed"); 5952 rc = EFAULT; 5953 goto out; 5954 } 5955 sfba = FBA_NUM(off + copied); 5956 efba = FBA_NUM(off + copied + len); 5957 for (index = 0; index < veccnt; index++) { 5958 krdc = &rdc_k_info[vec[index]]; 5959 urdc = &rdc_u_info[vec[index]]; 5960 5961 mutex_enter(&krdc->bmapmutex); 5962 if (op == RDC_BITMAPSET) { 5963 bcopy(ormem, krdc->dcio_bitmap + off + copied, 5964 len); 5965 } else { 5966 rdc_lor(ormem, 5967 krdc->dcio_bitmap + off + copied, len); 5968 } 5969 /* 5970 * Maybe this should be just done once outside of 5971 * the the loop? (Less work, but leaves a window 5972 * where the bits_set doesn't match the bitmap). 5973 */ 5974 urdc->bits_set = RDC_COUNT_BITMAP(krdc); 5975 mutex_exit(&krdc->bmapmutex); 5976 if (krdc->bitmap_write > 0) { 5977 for (fba = sfba; fba < efba; fba++) { 5978 if (rc = rdc_write_bitmap_fba(krdc, 5979 fba)) { 5980 5981 cmn_err(CE_WARN, 5982 "!installbitmap: " 5983 "write_bitmap_fba failed " 5984 "on fba number %" NSC_SZFMT 5985 " set %s:%s", fba, 5986 urdc->secondary.intf, 5987 urdc->secondary.file); 5988 goto out; 5989 } 5990 } 5991 } 5992 } 5993 copied += len; 5994 left -= len; 5995 } 5996 out: 5997 kmem_free(ormem, RDC_MAXDATA); 5998 return (rc); 5999 } 6000 6001 /* 6002 * _rdc_config 6003 */ 6004 int 6005 _rdc_config(void *arg, int mode, spcs_s_info_t kstatus, int *rvp) 6006 { 6007 int rc = 0; 6008 struct netbuf fsvaddr, tsvaddr; 6009 struct knetconfig *knconf; 6010 char *p = NULL, *pf = NULL; 6011 struct rdc_config *uap; 6012 STRUCT_DECL(knetconfig, knconf_tmp); 6013 STRUCT_DECL(rdc_config, uparms); 6014 int enable, disable; 6015 int cmd; 6016 6017 6018 STRUCT_HANDLE(rdc_set, rs); 6019 STRUCT_HANDLE(rdc_addr, pa); 6020 STRUCT_HANDLE(rdc_addr, sa); 6021 6022 STRUCT_INIT(uparms, mode); 6023 6024 bzero(STRUCT_BUF(uparms), STRUCT_SIZE(uparms)); 6025 bzero(&fsvaddr, sizeof (fsvaddr)); 6026 bzero(&tsvaddr, sizeof (tsvaddr)); 6027 6028 knconf = NULL; 6029 6030 if (ddi_copyin(arg, STRUCT_BUF(uparms), STRUCT_SIZE(uparms), mode)) { 6031 return (EFAULT); 6032 } 6033 6034 STRUCT_SET_HANDLE(rs, mode, STRUCT_FGETP(uparms, rdc_set)); 6035 STRUCT_SET_HANDLE(pa, mode, STRUCT_FADDR(rs, primary)); 6036 STRUCT_SET_HANDLE(sa, mode, STRUCT_FADDR(rs, secondary)); 6037 cmd = STRUCT_FGET(uparms, command); 6038 if (cmd == RDC_CMD_ENABLE || cmd == RDC_CMD_RESUME) { 6039 fsvaddr.len = STRUCT_FGET(pa, addr.len); 6040 fsvaddr.maxlen = STRUCT_FGET(pa, addr.maxlen); 6041 fsvaddr.buf = kmem_zalloc(fsvaddr.len, KM_SLEEP); 6042 6043 if (ddi_copyin(STRUCT_FGETP(pa, addr.buf), 6044 fsvaddr.buf, fsvaddr.len, mode)) { 6045 kmem_free(fsvaddr.buf, fsvaddr.len); 6046 #ifdef DEBUG 6047 cmn_err(CE_WARN, "!copyin failed primary.addr 2"); 6048 #endif 6049 return (EFAULT); 6050 } 6051 6052 6053 tsvaddr.len = STRUCT_FGET(sa, addr.len); 6054 tsvaddr.maxlen = STRUCT_FGET(sa, addr.maxlen); 6055 tsvaddr.buf = kmem_zalloc(tsvaddr.len, KM_SLEEP); 6056 6057 if (ddi_copyin(STRUCT_FGETP(sa, addr.buf), 6058 tsvaddr.buf, tsvaddr.len, mode)) { 6059 #ifdef DEBUG 6060 cmn_err(CE_WARN, "!copyin failed secondary addr"); 6061 #endif 6062 kmem_free(fsvaddr.buf, fsvaddr.len); 6063 kmem_free(tsvaddr.buf, tsvaddr.len); 6064 return (EFAULT); 6065 } 6066 } else { 6067 fsvaddr.len = 0; 6068 fsvaddr.maxlen = 0; 6069 fsvaddr.buf = kmem_zalloc(fsvaddr.len, KM_SLEEP); 6070 tsvaddr.len = 0; 6071 tsvaddr.maxlen = 0; 6072 tsvaddr.buf = kmem_zalloc(tsvaddr.len, KM_SLEEP); 6073 } 6074 6075 if (STRUCT_FGETP(uparms, rdc_set->netconfig) != NULL) { 6076 STRUCT_INIT(knconf_tmp, mode); 6077 knconf = kmem_zalloc(sizeof (*knconf), KM_SLEEP); 6078 if (ddi_copyin(STRUCT_FGETP(uparms, rdc_set->netconfig), 6079 STRUCT_BUF(knconf_tmp), STRUCT_SIZE(knconf_tmp), mode)) { 6080 #ifdef DEBUG 6081 cmn_err(CE_WARN, "!copyin failed netconfig"); 6082 #endif 6083 kmem_free(fsvaddr.buf, fsvaddr.len); 6084 kmem_free(tsvaddr.buf, tsvaddr.len); 6085 kmem_free(knconf, sizeof (*knconf)); 6086 return (EFAULT); 6087 } 6088 6089 knconf->knc_semantics = STRUCT_FGET(knconf_tmp, knc_semantics); 6090 knconf->knc_protofmly = STRUCT_FGETP(knconf_tmp, knc_protofmly); 6091 knconf->knc_proto = STRUCT_FGETP(knconf_tmp, knc_proto); 6092 6093 #ifndef _SunOS_5_6 6094 if ((mode & DATAMODEL_LP64) == 0) { 6095 knconf->knc_rdev = 6096 expldev(STRUCT_FGET(knconf_tmp, knc_rdev)); 6097 } else { 6098 #endif 6099 knconf->knc_rdev = STRUCT_FGET(knconf_tmp, knc_rdev); 6100 #ifndef _SunOS_5_6 6101 } 6102 #endif 6103 6104 pf = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 6105 p = kmem_alloc(KNC_STRSIZE, KM_SLEEP); 6106 rc = ddi_copyin(knconf->knc_protofmly, pf, KNC_STRSIZE, mode); 6107 if (rc) { 6108 #ifdef DEBUG 6109 cmn_err(CE_WARN, "!copyin failed parms protofmly"); 6110 #endif 6111 rc = EFAULT; 6112 goto out; 6113 } 6114 rc = ddi_copyin(knconf->knc_proto, p, KNC_STRSIZE, mode); 6115 if (rc) { 6116 #ifdef DEBUG 6117 cmn_err(CE_WARN, "!copyin failed parms proto"); 6118 #endif 6119 rc = EFAULT; 6120 goto out; 6121 } 6122 knconf->knc_protofmly = pf; 6123 knconf->knc_proto = p; 6124 } /* !NULL netconfig */ 6125 6126 uap = kmem_alloc(sizeof (*uap), KM_SLEEP); 6127 6128 /* copy relevant parts of rdc_config to uap field by field */ 6129 6130 (void) strncpy(uap->rdc_set[0].primary.intf, STRUCT_FGETP(pa, intf), 6131 MAX_RDC_HOST_SIZE); 6132 (void) strncpy(uap->rdc_set[0].primary.file, STRUCT_FGETP(pa, file), 6133 NSC_MAXPATH); 6134 (void) strncpy(uap->rdc_set[0].primary.bitmap, STRUCT_FGETP(pa, bitmap), 6135 NSC_MAXPATH); 6136 uap->rdc_set[0].netconfig = knconf; 6137 uap->rdc_set[0].flags = STRUCT_FGET(uparms, rdc_set->flags); 6138 uap->rdc_set[0].index = STRUCT_FGET(uparms, rdc_set->index); 6139 uap->rdc_set[0].setid = STRUCT_FGET(uparms, rdc_set->setid); 6140 uap->rdc_set[0].sync_pos = STRUCT_FGET(uparms, rdc_set->sync_pos); 6141 uap->rdc_set[0].volume_size = STRUCT_FGET(uparms, rdc_set->volume_size); 6142 uap->rdc_set[0].bits_set = STRUCT_FGET(uparms, rdc_set->bits_set); 6143 uap->rdc_set[0].autosync = STRUCT_FGET(uparms, rdc_set->autosync); 6144 uap->rdc_set[0].maxqfbas = STRUCT_FGET(uparms, rdc_set->maxqfbas); 6145 uap->rdc_set[0].maxqitems = STRUCT_FGET(uparms, rdc_set->maxqitems); 6146 uap->rdc_set[0].asyncthr = STRUCT_FGET(uparms, rdc_set->asyncthr); 6147 uap->rdc_set[0].syshostid = STRUCT_FGET(uparms, rdc_set->syshostid); 6148 uap->rdc_set[0].primary.addr = fsvaddr; /* struct copy */ 6149 uap->rdc_set[0].secondary.addr = tsvaddr; /* struct copy */ 6150 6151 (void) strncpy(uap->rdc_set[0].secondary.intf, STRUCT_FGETP(sa, intf), 6152 MAX_RDC_HOST_SIZE); 6153 (void) strncpy(uap->rdc_set[0].secondary.file, STRUCT_FGETP(sa, file), 6154 NSC_MAXPATH); 6155 (void) strncpy(uap->rdc_set[0].secondary.bitmap, 6156 STRUCT_FGETP(sa, bitmap), NSC_MAXPATH); 6157 6158 (void) strncpy(uap->rdc_set[0].direct_file, 6159 STRUCT_FGETP(rs, direct_file), NSC_MAXPATH); 6160 6161 (void) strncpy(uap->rdc_set[0].group_name, STRUCT_FGETP(rs, group_name), 6162 NSC_MAXPATH); 6163 6164 (void) strncpy(uap->rdc_set[0].disk_queue, STRUCT_FGETP(rs, disk_queue), 6165 NSC_MAXPATH); 6166 6167 uap->command = STRUCT_FGET(uparms, command); 6168 uap->options = STRUCT_FGET(uparms, options); 6169 6170 enable = (uap->command == RDC_CMD_ENABLE || 6171 uap->command == RDC_CMD_RESUME); 6172 disable = (uap->command == RDC_CMD_DISABLE || 6173 uap->command == RDC_CMD_SUSPEND); 6174 6175 /* 6176 * Initialise the threadset if it has not already been done. 6177 * 6178 * This has to be done now, not in rdcattach(), because 6179 * rdcattach() can be called before nskernd is running (eg. 6180 * boot -r) in which case the nst_init() would fail and hence 6181 * the attach would fail. 6182 * 6183 * Threadset creation is locked by the rdc_conf_lock, 6184 * destruction is inherently single threaded as it is done in 6185 * _rdc_unload() which must be the last thing performed by 6186 * rdcdetach(). 6187 */ 6188 6189 if (enable && _rdc_ioset == NULL) { 6190 mutex_enter(&rdc_conf_lock); 6191 6192 if (_rdc_ioset == NULL) { 6193 rc = rdc_thread_configure(); 6194 } 6195 6196 mutex_exit(&rdc_conf_lock); 6197 6198 if (rc || _rdc_ioset == NULL) { 6199 spcs_s_add(kstatus, RDC_ENOTHREADS); 6200 rc = RDC_ENOTHREADS; 6201 goto outuap; 6202 } 6203 } 6204 switch (uap->command) { 6205 case RDC_CMD_ENABLE: 6206 rc = rdc_enable(uap, kstatus); 6207 break; 6208 case RDC_CMD_DISABLE: 6209 rc = rdc_disable(uap, kstatus); 6210 break; 6211 case RDC_CMD_COPY: 6212 rc = rdc_sync(uap, kstatus); 6213 break; 6214 case RDC_CMD_LOG: 6215 rc = rdc_log(uap, kstatus); 6216 break; 6217 case RDC_CMD_RECONFIG: 6218 rc = rdc_reconfig(uap, kstatus); 6219 break; 6220 case RDC_CMD_RESUME: 6221 rc = rdc_resume(uap, kstatus); 6222 break; 6223 case RDC_CMD_SUSPEND: 6224 rc = rdc_suspend(uap, kstatus); 6225 break; 6226 case RDC_CMD_TUNABLE: 6227 rc = rdc_tunable(uap, kstatus); 6228 break; 6229 case RDC_CMD_WAIT: 6230 rc = rdc_wait(uap, kstatus); 6231 break; 6232 case RDC_CMD_HEALTH: 6233 rc = rdc_health(uap, kstatus, rvp); 6234 break; 6235 case RDC_CMD_STATUS: 6236 rc = rdc_status(arg, mode, uap, kstatus); 6237 break; 6238 case RDC_CMD_RESET: 6239 rc = rdc_reset(uap, kstatus); 6240 break; 6241 case RDC_CMD_ADDQ: 6242 rc = rdc_add_diskq(uap, kstatus); 6243 break; 6244 case RDC_CMD_REMQ: 6245 if ((rc = rdc_rem_diskq(uap, kstatus)) != 0) 6246 break; 6247 /* FALLTHRU */ 6248 case RDC_CMD_KILLQ: 6249 rc = rdc_kill_diskq(uap, kstatus); 6250 break; 6251 case RDC_CMD_INITQ: 6252 rc = rdc_init_diskq(uap, kstatus); 6253 break; 6254 6255 default: 6256 rc = EINVAL; 6257 break; 6258 } 6259 6260 /* 6261 * Tune the threadset size after a successful rdc_set addition 6262 * or removal. 6263 */ 6264 if ((enable || disable) && rc == 0) { 6265 mutex_enter(&rdc_conf_lock); 6266 rdc_thread_tune(enable ? 2 : -2); 6267 mutex_exit(&rdc_conf_lock); 6268 } 6269 outuap: 6270 kmem_free(uap, sizeof (*uap)); 6271 out: 6272 kmem_free(fsvaddr.buf, fsvaddr.len); 6273 kmem_free(tsvaddr.buf, tsvaddr.len); 6274 if (pf) 6275 kmem_free(pf, KNC_STRSIZE); 6276 if (p) 6277 kmem_free(p, KNC_STRSIZE); 6278 if (knconf) 6279 kmem_free(knconf, sizeof (*knconf)); 6280 return (rc); 6281 } 6282 6283 6284 /* 6285 * krdc->group->lock held on entry to halt_sync() 6286 */ 6287 static void 6288 halt_sync(rdc_k_info_t *krdc) 6289 { 6290 rdc_u_info_t *urdc = &rdc_u_info[krdc->index]; 6291 6292 ASSERT(MUTEX_HELD(&krdc->group->lock)); 6293 ASSERT(IS_ENABLED(urdc)); 6294 6295 /* 6296 * If a sync is in progress, halt it 6297 */ 6298 if ((rdc_get_vflags(urdc) & RDC_PRIMARY) && 6299 (krdc->aux_state & RDC_AUXSYNCIP)) { 6300 krdc->disk_status = 1; 6301 6302 while (krdc->disk_status == 1) { 6303 if (cv_wait_sig(&krdc->haltcv, &krdc->group->lock) == 0) 6304 break; 6305 } 6306 } 6307 } 6308 6309 /* 6310 * return size in blocks 6311 */ 6312 uint64_t 6313 mirror_getsize(int index) 6314 { 6315 rdc_k_info_t *krdc; 6316 rdc_u_info_t *urdc; 6317 int rc, rs; 6318 nsc_size_t size; 6319 6320 krdc = &rdc_k_info[index]; 6321 urdc = &rdc_u_info[index]; 6322 6323 rc = _rdc_rsrv_devs(krdc, RDC_RAW, RDC_INTERNAL); 6324 rs = nsc_partsize(RDC_U_FD(krdc), &size); 6325 urdc->volume_size = size; 6326 if (rc == 0) 6327 _rdc_rlse_devs(krdc, RDC_RAW); 6328 6329 return (rs == 0 ? urdc->volume_size : 0); 6330 } 6331 6332 6333 /* 6334 * Create a new dataset for this transfer, and add it to the list 6335 * of datasets via the net_dataset pointer in the krdc. 6336 */ 6337 rdc_net_dataset_t * 6338 rdc_net_add_set(int index) 6339 { 6340 rdc_k_info_t *krdc; 6341 rdc_u_info_t *urdc; 6342 rdc_net_dataset_t *dset; 6343 6344 if (index >= rdc_max_sets) { 6345 cmn_err(CE_NOTE, "!rdc_net_add_set: bad index %d", index); 6346 return (NULL); 6347 } 6348 krdc = &rdc_k_info[index]; 6349 urdc = &rdc_u_info[index]; 6350 6351 dset = kmem_alloc(sizeof (*dset), KM_NOSLEEP); 6352 if (dset == NULL) { 6353 cmn_err(CE_NOTE, "!rdc_net_add_set: kmem_alloc failed"); 6354 return (NULL); 6355 } 6356 RDC_DSMEMUSE(sizeof (*dset)); 6357 dset->inuse = 1; 6358 dset->nitems = 0; 6359 dset->delpend = 0; 6360 dset->head = NULL; 6361 dset->tail = NULL; 6362 mutex_enter(&krdc->dc_sleep); 6363 6364 if (!IS_ENABLED(urdc)) { 6365 /* raced with a disable command */ 6366 kmem_free(dset, sizeof (*dset)); 6367 RDC_DSMEMUSE(-sizeof (*dset)); 6368 mutex_exit(&krdc->dc_sleep); 6369 return (NULL); 6370 } 6371 /* 6372 * Shared the id generator, (and the locks). 6373 */ 6374 mutex_enter(&rdc_net_hnd_id_lock); 6375 if (++rdc_net_hnd_id == 0) 6376 rdc_net_hnd_id = 1; 6377 dset->id = rdc_net_hnd_id; 6378 mutex_exit(&rdc_net_hnd_id_lock); 6379 6380 #ifdef DEBUG 6381 if (krdc->net_dataset != NULL) { 6382 rdc_net_dataset_t *dset2; 6383 for (dset2 = krdc->net_dataset; dset2; dset2 = dset2->next) { 6384 if (dset2->id == dset->id) { 6385 cmn_err(CE_PANIC, 6386 "rdc_net_add_set duplicate id %p:%d %p:%d", 6387 (void *)dset, dset->id, 6388 (void *)dset2, dset2->id); 6389 } 6390 } 6391 } 6392 #endif 6393 dset->next = krdc->net_dataset; 6394 krdc->net_dataset = dset; 6395 mutex_exit(&krdc->dc_sleep); 6396 6397 return (dset); 6398 } 6399 6400 /* 6401 * fetch the previously added dataset. 6402 */ 6403 rdc_net_dataset_t * 6404 rdc_net_get_set(int index, int id) 6405 { 6406 rdc_k_info_t *krdc; 6407 rdc_net_dataset_t *dset; 6408 6409 if (index >= rdc_max_sets) { 6410 cmn_err(CE_NOTE, "!rdc_net_get_set: bad index %d", index); 6411 return (NULL); 6412 } 6413 krdc = &rdc_k_info[index]; 6414 6415 mutex_enter(&krdc->dc_sleep); 6416 6417 dset = krdc->net_dataset; 6418 while (dset && (dset->id != id)) 6419 dset = dset->next; 6420 6421 if (dset) { 6422 dset->inuse++; 6423 } 6424 6425 mutex_exit(&krdc->dc_sleep); 6426 return (dset); 6427 } 6428 6429 /* 6430 * Decrement the inuse counter. Data may be freed. 6431 */ 6432 void 6433 rdc_net_put_set(int index, rdc_net_dataset_t *dset) 6434 { 6435 rdc_k_info_t *krdc; 6436 6437 if (index >= rdc_max_sets) { 6438 cmn_err(CE_NOTE, "!rdc_net_put_set: bad index %d", index); 6439 return; 6440 } 6441 krdc = &rdc_k_info[index]; 6442 6443 mutex_enter(&krdc->dc_sleep); 6444 dset->inuse--; 6445 ASSERT(dset->inuse >= 0); 6446 if ((dset->inuse == 0) && (dset->delpend)) { 6447 rdc_net_free_set(krdc, dset); 6448 } 6449 mutex_exit(&krdc->dc_sleep); 6450 } 6451 6452 /* 6453 * Mark that we are finished with this set. Decrement inuse 6454 * counter, mark as needing deletion, and 6455 * remove from linked list. 6456 */ 6457 void 6458 rdc_net_del_set(int index, rdc_net_dataset_t *dset) 6459 { 6460 rdc_k_info_t *krdc; 6461 6462 if (index >= rdc_max_sets) { 6463 cmn_err(CE_NOTE, "!rdc_net_del_set: bad index %d", index); 6464 return; 6465 } 6466 krdc = &rdc_k_info[index]; 6467 6468 mutex_enter(&krdc->dc_sleep); 6469 dset->inuse--; 6470 ASSERT(dset->inuse >= 0); 6471 dset->delpend = 1; 6472 if (dset->inuse == 0) { 6473 rdc_net_free_set(krdc, dset); 6474 } 6475 mutex_exit(&krdc->dc_sleep); 6476 } 6477 6478 /* 6479 * free all the memory associated with this set, and remove from 6480 * list. 6481 * Enters and exits with dc_sleep lock held. 6482 */ 6483 6484 void 6485 rdc_net_free_set(rdc_k_info_t *krdc, rdc_net_dataset_t *dset) 6486 { 6487 rdc_net_dataset_t **dsetp; 6488 #ifdef DEBUG 6489 int found = 0; 6490 #endif 6491 6492 ASSERT(MUTEX_HELD(&krdc->dc_sleep)); 6493 ASSERT(dset); 6494 for (dsetp = &krdc->net_dataset; *dsetp; dsetp = &((*dsetp)->next)) { 6495 if (*dsetp == dset) { 6496 *dsetp = dset->next; 6497 #ifdef DEBUG 6498 found = 1; 6499 #endif 6500 break; 6501 } 6502 } 6503 6504 #ifdef DEBUG 6505 if (found == 0) { 6506 cmn_err(CE_WARN, "!rdc_net_free_set: Unable to find " 6507 "dataset 0x%p in krdc list", (void *)dset); 6508 } 6509 #endif 6510 /* 6511 * unlinked from list. Free all the data 6512 */ 6513 rdc_ditemsfree(dset); 6514 /* 6515 * free my core. 6516 */ 6517 kmem_free(dset, sizeof (*dset)); 6518 RDC_DSMEMUSE(-sizeof (*dset)); 6519 } 6520 6521 6522 /* 6523 * Free all the dataitems and the data it points to. 6524 */ 6525 static void 6526 rdc_ditemsfree(rdc_net_dataset_t *dset) 6527 { 6528 rdc_net_dataitem_t *ditem; 6529 rdc_net_dataitem_t *nitem; 6530 6531 ditem = dset->head; 6532 6533 while (ditem) { 6534 nitem = ditem->next; 6535 kmem_free(ditem->dptr, ditem->mlen); 6536 RDC_DSMEMUSE(-ditem->mlen); 6537 dset->nitems--; 6538 kmem_free(ditem, sizeof (*ditem)); 6539 RDC_DSMEMUSE(-sizeof (*ditem)); 6540 ditem = nitem; 6541 } 6542 ASSERT(dset->nitems == 0); 6543 } 6544 6545 /* 6546 * allocate and initialize a rdc_aio_t 6547 */ 6548 rdc_aio_t * 6549 rdc_aio_tbuf_get(void *n, void *h, int pos, int len, int flag, int index, int s) 6550 { 6551 rdc_aio_t *p; 6552 6553 p = kmem_zalloc(sizeof (rdc_aio_t), KM_NOSLEEP); 6554 if (p == NULL) { 6555 #ifdef DEBUG 6556 cmn_err(CE_NOTE, "!_rdcaiotbufget: kmem_alloc failed bp aio"); 6557 #endif 6558 return (NULL); 6559 } else { 6560 p->next = n; /* overload */ 6561 p->handle = h; 6562 p->pos = pos; 6563 p->qpos = -1; 6564 p->len = len; 6565 p->flag = flag; 6566 p->index = index; 6567 p->iostatus = s; /* overload */ 6568 /* set up seq later, in case thr create fails */ 6569 } 6570 return (p); 6571 } 6572 6573 /* 6574 * rdc_aio_buf_get 6575 * get an aio_buf 6576 */ 6577 aio_buf_t * 6578 rdc_aio_buf_get(rdc_buf_t *h, int index) 6579 { 6580 aio_buf_t *p; 6581 6582 if (index >= rdc_max_sets) { 6583 cmn_err(CE_NOTE, "!rdc: rdc_aio_buf_get bad index %x", index); 6584 return (NULL); 6585 } 6586 6587 mutex_enter(&h->aio_lock); 6588 6589 p = h->rdc_anon; 6590 while (p && (p->kindex != index)) 6591 p = p->next; 6592 6593 mutex_exit(&h->aio_lock); 6594 return (p); 6595 } 6596 6597 /* 6598 * rdc_aio_buf_del 6599 * delete a aio_buf 6600 */ 6601 void 6602 rdc_aio_buf_del(rdc_buf_t *h, rdc_k_info_t *krdc) 6603 { 6604 aio_buf_t *p, **pp; 6605 6606 mutex_enter(&h->aio_lock); 6607 6608 p = NULL; 6609 for (pp = &h->rdc_anon; *pp; pp = &((*pp)->next)) { 6610 if ((*pp)->kindex == krdc->index) { 6611 p = *pp; 6612 break; 6613 } 6614 } 6615 6616 if (p) { 6617 *pp = p->next; 6618 kmem_free(p, sizeof (*p)); 6619 } 6620 mutex_exit(&h->aio_lock); 6621 } 6622 6623 /* 6624 * rdc_aio_buf_add 6625 * Add a aio_buf. 6626 */ 6627 aio_buf_t * 6628 rdc_aio_buf_add(int index, rdc_buf_t *h) 6629 { 6630 aio_buf_t *p; 6631 6632 p = kmem_zalloc(sizeof (*p), KM_NOSLEEP); 6633 if (p == NULL) { 6634 cmn_err(CE_NOTE, "!rdc_aio_buf_add: kmem_alloc failed"); 6635 return (NULL); 6636 } 6637 6638 p->rdc_abufp = NULL; 6639 p->kindex = index; 6640 6641 mutex_enter(&h->aio_lock); 6642 p->next = h->rdc_anon; 6643 h->rdc_anon = p; 6644 mutex_exit(&h->aio_lock); 6645 return (p); 6646 } 6647 6648 /* 6649 * kmemalloc a new group structure and setup the common 6650 * fields. 6651 */ 6652 static rdc_group_t * 6653 rdc_newgroup() 6654 { 6655 rdc_group_t *group; 6656 6657 group = kmem_zalloc(sizeof (rdc_group_t), KM_SLEEP); 6658 group->diskq.lastio = kmem_zalloc(sizeof (rdc_aio_t), KM_SLEEP); 6659 group->count = 1; 6660 group->seq = RDC_NEWSEQ; 6661 group->seqack = RDC_NEWSEQ; 6662 mutex_init(&group->lock, NULL, MUTEX_DRIVER, NULL); 6663 mutex_init(&group->ra_queue.net_qlock, NULL, MUTEX_DRIVER, NULL); 6664 mutex_init(&group->diskqmutex, NULL, MUTEX_DRIVER, NULL); 6665 mutex_init(&group->diskq.disk_qlock, NULL, MUTEX_DRIVER, NULL); 6666 mutex_init(&group->diskq.head_lock, NULL, MUTEX_DRIVER, NULL); 6667 mutex_init(&group->addthrnumlk, NULL, MUTEX_DRIVER, NULL); 6668 cv_init(&group->unregistercv, NULL, CV_DRIVER, NULL); 6669 cv_init(&group->asyncqcv, NULL, CV_DRIVER, NULL); 6670 cv_init(&group->diskq.busycv, NULL, CV_DRIVER, NULL); 6671 cv_init(&group->diskq.qfullcv, NULL, CV_DRIVER, NULL); 6672 cv_init(&group->ra_queue.qfcv, NULL, CV_DRIVER, NULL); 6673 group->ra_queue.qfill_sleeping = RDC_QFILL_DEAD; 6674 group->diskq.busycnt = 0; 6675 ASSERT(group->synccount == 0); /* group was kmem_zalloc'ed */ 6676 6677 /* 6678 * add default number of threads to the flusher thread set, plus 6679 * one extra thread for the disk queue flusher 6680 */ 6681 if (nst_add_thread(_rdc_flset, 3) != 3) 6682 cmn_err(CE_NOTE, "!rdc_newgroup: nst_add_thread failed"); 6683 6684 return (group); 6685 } 6686 6687 void 6688 rdc_delgroup(rdc_group_t *group) 6689 { 6690 6691 ASSERT(group->asyncstall == 0); 6692 ASSERT(group->rdc_thrnum == 0); 6693 ASSERT(group->count == 0); 6694 ASSERT(MUTEX_HELD(&rdc_many_lock)); 6695 6696 mutex_enter(&group->ra_queue.net_qlock); 6697 rdc_sleepqdiscard(group); 6698 mutex_exit(&group->ra_queue.net_qlock); 6699 6700 /* try to remove flusher threads that this group added to _rdc_flset */ 6701 if (nst_del_thread(_rdc_flset, group->rdc_addthrnum + 3) != 6702 group->rdc_addthrnum + 3) 6703 cmn_err(CE_NOTE, "!rdc_delgroup: nst_del_thread failed"); 6704 6705 mutex_destroy(&group->lock); 6706 mutex_destroy(&group->ra_queue.net_qlock); 6707 mutex_destroy(&group->diskqmutex); 6708 mutex_destroy(&group->diskq.disk_qlock); 6709 mutex_destroy(&group->diskq.head_lock); 6710 mutex_destroy(&group->addthrnumlk); 6711 cv_destroy(&group->unregistercv); 6712 cv_destroy(&group->asyncqcv); 6713 cv_destroy(&group->diskq.busycv); 6714 cv_destroy(&group->diskq.qfullcv); 6715 cv_destroy(&group->ra_queue.qfcv); 6716 kmem_free(group->diskq.lastio, sizeof (rdc_aio_t)); 6717 kmem_free(group, sizeof (rdc_group_t)); 6718 }