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