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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Creates and maintains a cache of slices used by SVM. 31 */ 32 33 #include <meta.h> 34 #include <stdlib.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <libintl.h> 38 #include <synch.h> 39 #include <thread.h> 40 #include <dlfcn.h> 41 #include <link.h> 42 #include <libsysevent.h> 43 #include <syslog.h> 44 #include <sys/types.h> 45 #include <sys/sysevent/eventdefs.h> 46 47 #include "libdiskmgt.h" 48 #include "disks_private.h" 49 50 /* 51 * The list of SVM slices in use. 52 */ 53 54 struct svm_list { 55 struct svm_list *next; 56 char *slice; 57 char *name; 58 char *type; 59 }; 60 61 static struct svm_list *svm_listp = NULL; 62 static rwlock_t svm_lock = DEFAULTRWLOCK; 63 static int initialized = 0; 64 static mutex_t init_lock = DEFAULTMUTEX; 65 66 static int add_use_record(char *devname, char *type, char *mname); 67 static int diskset_info(mdsetname_t *sp); 68 static int drive_in_diskset(char *dpath, char *setname); 69 static void event_handler(); 70 static void free_names(mdnamelist_t *nlp); 71 static void free_svm(struct svm_list *listp); 72 static int init_svm(); 73 static int load_svm(); 74 static int new_entry(char *sname, char *type, char *mname, 75 mdsetname_t *sp); 76 77 /* 78 * Pointers to libmeta functions that we dynamically resolve. 79 */ 80 static set_t (*mdl_get_max_sets)(md_error_t *ep); 81 static void (*mdl_mdclrerror)(md_error_t *ep); 82 static md_error_t *mdl_mdnullerror; 83 static void (*mdl_metaflushnames)(int flush_sr_cache); 84 static void (*mdl_metaflushsetname)(mdsetname_t *sp); 85 static void (*mdl_metafreenamelist)(mdnamelist_t *nlp); 86 static void (*mdl_metafreereplicalist)(md_replicalist_t *rlp); 87 static md_drive_desc *(*mdl_metaget_drivedesc)(mdsetname_t *sp, int flags, 88 md_error_t *ep); 89 static mdname_t *(*mdl_metaname)(mdsetname_t **spp, char *uname, 90 md_error_t *ep); 91 static int (*mdl_metareplicalist)(mdsetname_t *sp, int flags, 92 md_replicalist_t **rlpp, md_error_t *ep); 93 static mdsetname_t *(*mdl_metasetnosetname)(set_t setno, md_error_t *ep); 94 static int (*mdl_meta_get_hotspare_names)(mdsetname_t *sp, 95 mdnamelist_t **nlpp, int options, md_error_t *ep); 96 static md_raid_t *(*mdl_meta_get_raid)(mdsetname_t *sp, mdname_t *raidnp, 97 md_error_t *ep); 98 static int (*mdl_meta_get_raid_names)(mdsetname_t *sp, 99 mdnamelist_t **nlpp, int options, md_error_t *ep); 100 static md_sp_t *(*mdl_meta_get_sp)(mdsetname_t *sp, mdname_t *np, 101 md_error_t *ep); 102 static int (*mdl_meta_get_sp_names)(mdsetname_t *sp, 103 mdnamelist_t **nlpp, int options, md_error_t *ep); 104 static md_stripe_t *(*mdl_meta_get_stripe)(mdsetname_t *sp, 105 mdname_t *stripenp, md_error_t *ep); 106 static int (*mdl_meta_get_stripe_names)(mdsetname_t *sp, 107 mdnamelist_t **nlpp, int options, md_error_t *ep); 108 static int (*mdl_meta_get_trans_names)(mdsetname_t *sp, 109 mdnamelist_t **nlpp, int options, md_error_t *ep); 110 static void (*mdl_meta_invalidate_name)(mdname_t *np); 111 static void (*mdl_sdssc_bind_library)(); 112 113 /* 114 * Search the list of devices under SVM for the specified device. 115 */ 116 int 117 inuse_svm(char *slice, nvlist_t *attrs, int *errp) 118 { 119 struct svm_list *listp; 120 int found = 0; 121 122 *errp = 0; 123 if (slice == NULL) { 124 return (found); 125 } 126 127 (void) mutex_lock(&init_lock); 128 if (!initialized) { 129 /* dynamically load libmeta */ 130 if (init_svm()) { 131 /* 132 * need to initialize the cluster library to 133 * avoid seg faults 134 */ 135 (mdl_sdssc_bind_library)(); 136 137 /* load the SVM cache */ 138 *errp = load_svm(); 139 140 if (*errp == 0) { 141 /* start a thread to monitor the svm config */ 142 sysevent_handle_t *shp; 143 const char *subclass_list[1]; 144 /* 145 * Only start the svmevent thread if 146 * we are not doing an install 147 */ 148 149 if (getenv("_LIBDISKMGT_INSTALL") == NULL) { 150 shp = sysevent_bind_handle( 151 event_handler); 152 if (shp != NULL) { 153 subclass_list[0] = EC_SUB_ALL; 154 if (sysevent_subscribe_event( 155 shp, EC_SVM_CONFIG, 156 subclass_list, 1) != 0) { 157 *errp = errno; 158 } 159 } else { 160 *errp = errno; 161 } 162 if (*errp) { 163 /* 164 * If the sysevent thread fails, 165 * log the error but continue 166 * on. This failing to start 167 * is not catastrophic in 168 * particular for short lived 169 * consumers of libdiskmgt. 170 */ 171 syslog(LOG_WARNING, 172 dgettext(TEXT_DOMAIN, 173 "libdiskmgt: sysevent " 174 "thread for SVM failed " 175 "to start\n")); 176 *errp = 0; 177 } 178 } 179 } 180 } 181 182 if (*errp == 0) { 183 initialized = 1; 184 } 185 } 186 (void) mutex_unlock(&init_lock); 187 188 (void) rw_rdlock(&svm_lock); 189 listp = svm_listp; 190 while (listp != NULL) { 191 if (strcmp(slice, listp->slice) == 0) { 192 libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_SVM, errp); 193 if (strcmp(listp->type, "mdb") == 0 || 194 strcmp(listp->type, "hs") == 0) { 195 196 libdiskmgt_add_str(attrs, DM_USED_NAME, listp->type, errp); 197 } else { 198 char name[MAXPATHLEN]; 199 (void) snprintf(name, MAXPATHLEN, "%s:%s", listp->type, 200 listp->name); 201 libdiskmgt_add_str(attrs, DM_USED_NAME, name, errp); 202 } 203 found = 1; 204 break; 205 } 206 listp = listp->next; 207 } 208 (void) rw_unlock(&svm_lock); 209 210 return (found); 211 } 212 213 static int 214 add_use_record(char *devname, char *type, char *mname) 215 { 216 struct svm_list *sp; 217 218 /* If prev. record is a dup, skip it. */ 219 if (svm_listp != NULL && strcmp(svm_listp->slice, devname) == 0 && 220 strcmp(svm_listp->type, type) == 0) { 221 return (0); 222 } 223 224 sp = (struct svm_list *)malloc(sizeof (struct svm_list)); 225 if (sp == NULL) { 226 return (ENOMEM); 227 } 228 229 if ((sp->slice = strdup(devname)) == NULL) { 230 free(sp); 231 return (ENOMEM); 232 } 233 234 if ((sp->name = strdup(mname)) == NULL) { 235 free(sp->slice); 236 free(sp); 237 return (ENOMEM); 238 } 239 240 if ((sp->type = strdup(type)) == NULL) { 241 free(sp->slice); 242 free(sp->name); 243 free(sp); 244 return (ENOMEM); 245 } 246 247 sp->next = svm_listp; 248 svm_listp = sp; 249 250 return (0); 251 } 252 253 static int 254 diskset_info(mdsetname_t *sp) 255 { 256 md_error_t error = *mdl_mdnullerror; 257 md_replicalist_t *replica_list = NULL; 258 mdnamelist_t *trans_list = NULL; 259 mdnamelist_t *raid_list = NULL; 260 mdnamelist_t *stripe_list = NULL; 261 mdnamelist_t *sp_list = NULL; 262 mdnamelist_t *spare_list = NULL; 263 264 if ((mdl_metareplicalist)(sp, MD_BASICNAME_OK, &replica_list, &error) 265 >= 0) { 266 md_replicalist_t *nlp; 267 268 for (nlp = replica_list; nlp != NULL; nlp = nlp->rl_next) { 269 if (new_entry(nlp->rl_repp->r_namep->bname, "mdb", 270 nlp->rl_repp->r_namep->cname, sp)) { 271 (mdl_metafreereplicalist)(replica_list); 272 return (ENOMEM); 273 } 274 } 275 (mdl_metafreereplicalist)(replica_list); 276 277 } else { 278 (mdl_mdclrerror)(&error); 279 /* there are no metadb's; that is ok, no need to check the rest */ 280 return (0); 281 } 282 (mdl_mdclrerror)(&error); 283 284 if ((mdl_meta_get_trans_names)(sp, &trans_list, 0, &error) >= 0) { 285 mdnamelist_t *nlp; 286 287 for (nlp = trans_list; nlp != NULL; nlp = nlp->next) { 288 if (new_entry(nlp->namep->bname, "trans", nlp->namep->cname, 289 sp)) { 290 free_names(trans_list); 291 return (ENOMEM); 292 } 293 } 294 295 free_names(trans_list); 296 } 297 (mdl_mdclrerror)(&error); 298 299 if ((mdl_meta_get_raid_names)(sp, &raid_list, 0, &error) >= 0) { 300 mdnamelist_t *nlp; 301 302 for (nlp = raid_list; nlp != NULL; nlp = nlp->next) { 303 mdname_t *mdn; 304 md_raid_t *raid; 305 306 mdn = (mdl_metaname)(&sp, nlp->namep->cname, &error); 307 (mdl_mdclrerror)(&error); 308 if (mdn == NULL) { 309 continue; 310 } 311 312 raid = (mdl_meta_get_raid)(sp, mdn, &error); 313 (mdl_mdclrerror)(&error); 314 315 if (raid != NULL) { 316 int i; 317 318 for (i = 0; i < raid->cols.cols_len; i++) { 319 if (new_entry(raid->cols.cols_val[i].colnamep->bname, 320 "raid", nlp->namep->cname, sp)) { 321 free_names(raid_list); 322 return (ENOMEM); 323 } 324 } 325 } 326 } 327 328 free_names(raid_list); 329 } 330 (mdl_mdclrerror)(&error); 331 332 if ((mdl_meta_get_stripe_names)(sp, &stripe_list, 0, &error) >= 0) { 333 mdnamelist_t *nlp; 334 335 for (nlp = stripe_list; nlp != NULL; nlp = nlp->next) { 336 mdname_t *mdn; 337 md_stripe_t *stripe; 338 339 mdn = (mdl_metaname)(&sp, nlp->namep->cname, &error); 340 (mdl_mdclrerror)(&error); 341 if (mdn == NULL) { 342 continue; 343 } 344 345 stripe = (mdl_meta_get_stripe)(sp, mdn, &error); 346 (mdl_mdclrerror)(&error); 347 348 if (stripe != NULL) { 349 int i; 350 351 for (i = 0; i < stripe->rows.rows_len; i++) { 352 md_row_t *rowp; 353 int j; 354 355 rowp = &stripe->rows.rows_val[i]; 356 357 for (j = 0; j < rowp->comps.comps_len; j++) { 358 md_comp_t *component; 359 360 component = &rowp->comps.comps_val[j]; 361 if (new_entry(component->compnamep->bname, "stripe", 362 nlp->namep->cname, sp)) { 363 free_names(stripe_list); 364 return (ENOMEM); 365 } 366 } 367 } 368 } 369 } 370 371 free_names(stripe_list); 372 } 373 (mdl_mdclrerror)(&error); 374 375 if ((mdl_meta_get_sp_names)(sp, &sp_list, 0, &error) >= 0) { 376 mdnamelist_t *nlp; 377 378 for (nlp = sp_list; nlp != NULL; nlp = nlp->next) { 379 mdname_t *mdn; 380 md_sp_t *soft_part; 381 382 mdn = (mdl_metaname)(&sp, nlp->namep->cname, &error); 383 (mdl_mdclrerror)(&error); 384 if (mdn == NULL) { 385 continue; 386 } 387 388 soft_part = (mdl_meta_get_sp)(sp, mdn, &error); 389 (mdl_mdclrerror)(&error); 390 391 if (soft_part != NULL) { 392 if (new_entry(soft_part->compnamep->bname, "sp", 393 nlp->namep->cname, sp)) { 394 free_names(sp_list); 395 return (ENOMEM); 396 } 397 } 398 } 399 400 free_names(sp_list); 401 } 402 (mdl_mdclrerror)(&error); 403 404 if ((mdl_meta_get_hotspare_names)(sp, &spare_list, 0, &error) >= 0) { 405 mdnamelist_t *nlp; 406 407 for (nlp = spare_list; nlp != NULL; nlp = nlp->next) { 408 if (new_entry(nlp->namep->bname, "hs", nlp->namep->cname, sp)) { 409 free_names(spare_list); 410 return (ENOMEM); 411 } 412 } 413 414 free_names(spare_list); 415 } 416 417 (mdl_mdclrerror)(&error); 418 419 return (0); 420 } 421 422 /* 423 * SVM uses "drive names" (ctd name without trailing slice) for drives 424 * in disksets. Since it massages these names there is no direct correspondence 425 * with the slice device names in /dev. So, we need to massage these names 426 * back to something we can match on when a slice comes in. We create an 427 * entry for each possible slice since we don't know what slices actually 428 * exist. Slice 0 & 7 are probably enough, but the user could have 429 * repartitioned the drive after they added it to the diskset and removed the 430 * mdb. 431 */ 432 static int 433 drive_in_diskset(char *dpath, char *setname) 434 { 435 int i; 436 char path[MAXPATHLEN]; 437 438 (void) strlcpy(path, dpath, sizeof (path)); 439 if (strncmp(path, "/dev/rdsk/", 10) == 0) { 440 /* change rdsk to dsk */ 441 char *p; 442 443 /* start p pointing to r in rdsk */ 444 for (p = path + 5; *p; p++) { 445 *p = *(p + 1); 446 } 447 } else if (strncmp(path, "/dev/did/rdsk/", 14) == 0) { 448 /* change rdsk to dsk */ 449 char *p; 450 451 /* start p pointing to r in rdsk */ 452 for (p = path + 9; *p; p++) { 453 *p = *(p + 1); 454 } 455 } 456 457 for (i = 0; i < 8; i++) { 458 char slice[MAXPATHLEN]; 459 460 (void) snprintf(slice, sizeof (slice), "%ss%d", path, i); 461 if (add_use_record(slice, "diskset", setname)) { 462 return (ENOMEM); 463 } 464 } 465 466 return (0); 467 } 468 469 static void 470 event_handler() 471 { 472 (void) rw_wrlock(&svm_lock); 473 free_svm(svm_listp); 474 svm_listp = NULL; 475 (mdl_metaflushnames)(0); 476 (void) load_svm(); 477 (void) rw_unlock(&svm_lock); 478 } 479 480 static void 481 free_names(mdnamelist_t *nlp) 482 { 483 mdnamelist_t *p; 484 485 for (p = nlp; p != NULL; p = p->next) { 486 (mdl_meta_invalidate_name)(p->namep); 487 p->namep = NULL; 488 } 489 (mdl_metafreenamelist)(nlp); 490 } 491 492 /* 493 * Free the list of SVM entries. 494 */ 495 static void 496 free_svm(struct svm_list *listp) { 497 498 struct svm_list *nextp; 499 500 while (listp != NULL) { 501 nextp = listp->next; 502 free((void *)listp->slice); 503 free((void *)listp->name); 504 free((void *)listp->type); 505 free((void *)listp); 506 listp = nextp; 507 } 508 } 509 510 /* 511 * Try to dynamically link the libmeta functions we need. 512 */ 513 static int 514 init_svm() 515 { 516 void *lh; 517 518 if ((lh = dlopen("/usr/lib/libmeta.so", RTLD_NOW)) == NULL) { 519 return (0); 520 } 521 522 mdl_get_max_sets = (set_t (*)(md_error_t *))dlsym(lh, "get_max_sets"); 523 524 mdl_mdclrerror = (void(*)(md_error_t *))dlsym(lh, "mdclrerror"); 525 526 mdl_mdnullerror = (md_error_t *)dlsym(lh, "mdnullerror"); 527 528 mdl_metaflushnames = (void (*)(int))dlsym(lh, "metaflushnames"); 529 530 mdl_metaflushsetname = (void (*)(mdsetname_t *))dlsym(lh, 531 "metaflushsetname"); 532 533 mdl_metafreenamelist = (void (*)(mdnamelist_t *))dlsym(lh, 534 "metafreenamelist"); 535 536 mdl_metafreereplicalist = (void (*)(md_replicalist_t *))dlsym(lh, 537 "metafreereplicalist"); 538 539 mdl_metaget_drivedesc = (md_drive_desc *(*)(mdsetname_t *, int, 540 md_error_t *))dlsym(lh, "metaget_drivedesc"); 541 542 mdl_metaname = (mdname_t *(*)(mdsetname_t **, char *, md_error_t *)) 543 dlsym(lh, "metaname"); 544 545 mdl_metareplicalist = (int (*)(mdsetname_t *, int, md_replicalist_t **, 546 md_error_t *))dlsym(lh, "metareplicalist"); 547 548 mdl_metasetnosetname = (mdsetname_t *(*)(set_t, md_error_t *))dlsym(lh, 549 "metasetnosetname"); 550 551 mdl_meta_get_hotspare_names = (int (*)(mdsetname_t *, mdnamelist_t **, 552 int, md_error_t *))dlsym(lh, "meta_get_hotspare_names"); 553 554 mdl_meta_get_raid = (md_raid_t *(*)(mdsetname_t *, mdname_t *, 555 md_error_t *))dlsym(lh, "meta_get_raid"); 556 557 mdl_meta_get_raid_names = (int (*)(mdsetname_t *, mdnamelist_t **, 558 int, md_error_t *))dlsym(lh, "meta_get_raid_names"); 559 560 mdl_meta_get_sp = (md_sp_t *(*)(mdsetname_t *, mdname_t *, 561 md_error_t *))dlsym(lh, "meta_get_sp"); 562 563 mdl_meta_get_sp_names = (int (*)(mdsetname_t *, mdnamelist_t **, 564 int, md_error_t *))dlsym(lh, "meta_get_sp_names"); 565 566 mdl_meta_get_stripe = (md_stripe_t *(*)(mdsetname_t *, mdname_t *, 567 md_error_t *))dlsym(lh, "meta_get_stripe"); 568 569 mdl_meta_get_stripe_names = (int (*)(mdsetname_t *, mdnamelist_t **, 570 int, md_error_t *))dlsym(lh, "meta_get_stripe_names"); 571 572 mdl_meta_get_trans_names = (int (*)(mdsetname_t *, mdnamelist_t **, 573 int, md_error_t *))dlsym(lh, "meta_get_trans_names"); 574 575 mdl_meta_invalidate_name = (void (*)(mdname_t *))dlsym(lh, 576 "meta_invalidate_name"); 577 578 mdl_sdssc_bind_library = (void (*)())dlsym(lh, "sdssc_bind_library"); 579 580 return (1); 581 } 582 583 /* 584 * Create a list of SVM devices 585 */ 586 static int 587 load_svm() 588 { 589 int max_sets; 590 md_error_t error = *mdl_mdnullerror; 591 int i; 592 593 if ((max_sets = (mdl_get_max_sets)(&error)) == 0) { 594 return (0); 595 } 596 597 if (!mdisok(&error)) { 598 (mdl_mdclrerror)(&error); 599 return (0); 600 } 601 602 /* for each possible set number, see if we really have a diskset */ 603 for (i = 0; i < max_sets; i++) { 604 mdsetname_t *sp; 605 606 if ((sp = (mdl_metasetnosetname)(i, &error)) == NULL) { 607 608 if (!mdisok(&error) && 609 mdisrpcerror(&error, RPC_PROGNOTREGISTERED)) { 610 /* metad rpc program not registered - no metasets */ 611 break; 612 } 613 614 (mdl_mdclrerror)(&error); 615 continue; 616 } 617 (mdl_mdclrerror)(&error); 618 619 /* pick up drives in disksets with no mdbs/metadevices */ 620 if (sp->setno != 0) { 621 md_drive_desc *dd; 622 623 dd = (mdl_metaget_drivedesc)(sp, MD_BASICNAME_OK | PRINT_FAST, 624 &error); 625 (mdl_mdclrerror)(&error); 626 for (; dd != NULL; dd = dd->dd_next) { 627 if (drive_in_diskset(dd->dd_dnp->rname, sp->setname)) { 628 (mdl_metaflushsetname)(sp); 629 return (ENOMEM); 630 } 631 } 632 } 633 634 if (diskset_info(sp)) { 635 (mdl_metaflushsetname)(sp); 636 return (ENOMEM); 637 } 638 639 (mdl_metaflushsetname)(sp); 640 } 641 642 (mdl_mdclrerror)(&error); 643 644 return (0); 645 } 646 647 static int 648 new_entry(char *sname, char *type, char *mname, mdsetname_t *sp) 649 { 650 mdname_t *mdn; 651 md_error_t error = *mdl_mdnullerror; 652 653 mdn = (mdl_metaname)(&sp, sname, &error); 654 if (!mdisok(&error)) { 655 (mdl_mdclrerror)(&error); 656 return (0); 657 } 658 659 if (mdn != NULL && ( 660 mdn->drivenamep->type == MDT_ACCES || 661 mdn->drivenamep->type == MDT_COMP || 662 mdn->drivenamep->type == MDT_FAST_COMP)) { 663 664 return (add_use_record(mdn->bname, type, mname)); 665 } 666 667 return (0); 668 } 669