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