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