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 #include <stdio.h> 29 #include <errno.h> 30 #include <unistd.h> 31 #include <string.h> 32 33 #include <meta.h> 34 #include <sys/lvm/md_mddb.h> 35 #include <sdssc.h> 36 37 /* 38 * print metadevice status 39 */ 40 41 42 #define MD_PROBE_OPEN_T "probe open test" 43 44 /* used to keep track of the softparts on the same underlying device */ 45 struct sp_base_list { 46 struct sp_base_list *next; 47 char *base; 48 }; 49 50 /* 51 * Function prototypes 52 */ 53 static void probe_all_devs(mdsetname_t *sp); 54 55 static int print_devid(mdsetname_t *sp, mdnamelist_t *nlp, FILE *fp, 56 md_error_t *ep); 57 58 static md_common_t *get_concise_unit(mdsetname_t *sp, mdname_t *np, 59 md_error_t *ep); 60 static void print_all_sets(mdprtopts_t options, int concise_flag, 61 int quiet_flg); 62 static void print_specific_set(mdsetname_t *sp, mdprtopts_t options, 63 int concise_flag, int quiet_flg); 64 static void print_concise_diskset(mdsetname_t *sp); 65 static void print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl, 66 char mtype); 67 static void print_concise_md(int indent, mdsetname_t *sp, mdname_t *np); 68 static void print_concise_mirror(int indent, mdsetname_t *sp, 69 md_mirror_t *mirror); 70 static void print_concise_raid(int indent, mdsetname_t *sp, 71 md_raid_t *raid); 72 static void print_concise_stripe(int indent, mdsetname_t *sp, 73 md_stripe_t *stripe); 74 static void print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part); 75 static void print_concise_trans(int indent, mdsetname_t *sp, 76 md_trans_t *trans); 77 static void free_names(mdnamelist_t **nlp); 78 static char *get_sm_state(md_mirror_t *mirror, int i, 79 md_status_t mirror_status, uint_t tstate); 80 static char *get_raid_col_state(md_raidcol_t *colp, uint_t tstate); 81 static char *get_stripe_state(md_comp_t *mdcp, uint_t tstate); 82 static char *get_hs_state(md_hs_t *hsp); 83 static struct sp_base_list *sp_add_done(md_sp_t *part, struct sp_base_list *lp); 84 static int sp_done(md_sp_t *part, struct sp_base_list *lp); 85 static int sp_match(md_sp_t *part, struct sp_base_list *lp); 86 static void sp_free_list(struct sp_base_list *lp); 87 88 89 /* 90 * print named hotspare pool or metadevice 91 */ 92 static int 93 print_name( 94 mdsetname_t **spp, 95 char *uname, 96 mdnamelist_t **nlistpp, 97 char *fname, 98 FILE *fp, 99 mdprtopts_t options, 100 int *meta_print_trans_msgp, 101 mdnamelist_t **lognlpp, 102 md_error_t *ep 103 ) 104 { 105 mdname_t *namep; 106 char *miscname; 107 108 /* recurse */ 109 options |= PRINT_SUBDEVS; 110 111 /* hotspare pool */ 112 if (is_existing_hsp(*spp, uname)) { 113 mdhspname_t *hspnamep; 114 115 /* get hotsparepool */ 116 if ((hspnamep = metahspname(spp, uname, ep)) == NULL) 117 return (-1); 118 119 /* check for ownership */ 120 assert(*spp != NULL); 121 if (meta_check_ownership(*spp, ep) != 0) 122 return (-1); 123 124 /* print hotspare pool */ 125 return (meta_hsp_print(*spp, hspnamep, lognlpp, fname, fp, 126 options, ep)); 127 } 128 129 /* get metadevice */ 130 if (((namep = metaname(spp, uname, META_DEVICE, ep)) == NULL) || 131 (metachkmeta(namep, ep) != 0)) 132 return (-1); 133 134 /* check for ownership */ 135 assert(*spp != NULL); 136 if (meta_check_ownership(*spp, ep) != 0) 137 return (-1); 138 139 if ((miscname = metagetmiscname(namep, ep)) != NULL) { 140 if (strcmp(miscname, MD_TRANS) == 0) { 141 *meta_print_trans_msgp = 1; 142 } 143 } 144 145 /* print metadevice */ 146 return (meta_print_name(*spp, namep, nlistpp, fname, fp, options, 147 lognlpp, ep)); 148 } 149 150 /* 151 * print the per set flags 152 */ 153 /*ARGSUSED*/ 154 static int 155 print_setstat( 156 mdsetname_t **spp, 157 char *fname, 158 FILE *fp, 159 mdprtopts_t options, 160 md_error_t *ep 161 ) 162 { 163 int rval = -1; 164 char *cname = NULL; 165 char *cp = NULL; 166 md_gs_stat_parm_t gsp; 167 168 169 if (fname != NULL && strchr(fname, '/') != NULL) { 170 /* get the canonical name */ 171 cname = meta_name_getname(spp, fname, META_DEVICE, ep); 172 if (cname == NULL) { 173 mde_perror(ep, ""); 174 mdclrerror(ep); 175 return (-1); 176 } 177 Free(cname); 178 } 179 180 if ((cp = getenv("MD_DEBUG")) == NULL) 181 return (0); 182 183 if (strstr(cp, "SETINFO") == NULL) 184 return (0); 185 186 (void) memset(&gsp, '\0', sizeof (md_gs_stat_parm_t)); 187 gsp.gs_setno = (*spp)->setno; 188 189 if (metaioctl(MD_GET_SETSTAT, &gsp, &gsp.gs_mde, NULL) != 0) 190 return (mdstealerror(ep, &gsp.gs_mde)); 191 192 if (fprintf(fp, "Status for set %d = ", gsp.gs_setno) == EOF) 193 goto out; 194 195 if (meta_prbits(fp, NULL, gsp.gs_status, MD_SET_STAT_BITS) == EOF) 196 goto out; 197 198 199 if (fprintf(fp, "\n") == EOF) 200 goto out; 201 202 /* success */ 203 rval = 0; 204 205 /* cleanup, return error */ 206 out: 207 if (rval != 0) 208 (void) mdsyserror(ep, errno, fname); 209 210 return (rval); 211 } 212 213 /* 214 * check_replica_state: 215 * If the replica state is stale or the set has been halted 216 * this routine returns an error. 217 */ 218 static int 219 check_replica_state(mdsetname_t *sp, md_error_t *ep) 220 { 221 mddb_config_t c; 222 223 (void) memset(&c, 0, sizeof (c)); 224 c.c_id = 0; 225 c.c_setno = sp->setno; 226 227 if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0) { 228 if (mdismddberror(&c.c_mde, MDE_DB_INVALID)) 229 mdstealerror(ep, &c.c_mde); 230 return (-1); 231 } 232 233 if (c.c_flags & MDDB_C_STALE) { 234 return (mdmddberror(ep, MDE_DB_STALE, NODEV32, sp->setno, 235 0, NULL)); 236 } else 237 return (0); 238 } 239 240 static void 241 print_trans_msg(mdprtopts_t options, int meta_print_trans_msg) 242 { 243 if (meta_print_trans_msg != 0) { 244 fprintf(stderr, "\n\n"); 245 if (options & PRINT_SHORT) { 246 fprintf(stderr, gettext(MD_SHORT_EOF_TRANS_MSG)); 247 fprintf(stderr, gettext(MD_SHORT_EOF_TRANS_WARNING)); 248 } else { 249 fprintf(stderr, gettext(MD_EOF_TRANS_MSG)); 250 fprintf(stderr, gettext(MD_EOF_TRANS_WARNING)); 251 } 252 } 253 } 254 255 /* 256 * print usage message 257 * 258 */ 259 static void 260 usage( 261 mdsetname_t *sp, 262 int eval 263 ) 264 { 265 (void) fprintf(stderr, gettext("\ 266 usage: %s [-s setname] [-a][-c][-B][-D][-r][-i][-p] [-t] [metadevice...]\n"), 267 myname); 268 md_exit(sp, eval); 269 } 270 271 /* 272 * mainline. crack command line arguments. 273 */ 274 int 275 main( 276 int argc, 277 char *argv[] 278 ) 279 { 280 char *sname = MD_LOCAL_NAME; 281 mdsetname_t *sp = NULL; 282 mdprtopts_t options = PRINT_HEADER | PRINT_DEVID | PRINT_FAST; 283 int c; 284 char *p; 285 md_error_t status = mdnullerror; 286 md_error_t *ep = &status; 287 int eval = 0; 288 int inquire = 0; 289 int quiet_flg = 0; 290 int set_flg = 0; 291 int error; 292 int all_sets_flag = 0; 293 int concise_flag = 0; 294 mdnamelist_t *nlistp = NULL; 295 mdname_t *namep; 296 int devcnt = 0; 297 mdnamelist_t *lognlp = NULL; 298 uint_t hsi; 299 int meta_print_trans_msg = 0; 300 301 /* 302 * Get the locale set up before calling any other routines 303 * with messages to ouput. Just in case we're not in a build 304 * environment, make sure that TEXT_DOMAIN gets set to 305 * something. 306 */ 307 #if !defined(TEXT_DOMAIN) 308 #define TEXT_DOMAIN "SYS_TEST" 309 #endif 310 (void) setlocale(LC_ALL, ""); 311 (void) textdomain(TEXT_DOMAIN); 312 313 if (sdssc_bind_library() == SDSSC_OKAY) 314 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 315 &error) == SDSSC_PROXY_DONE) 316 exit(error); 317 318 /* initialize */ 319 if (md_init(argc, argv, 0, 1, ep) != 0) { 320 mde_perror(ep, ""); 321 md_exit(sp, 1); 322 } 323 324 /* parse arguments */ 325 optind = 1; 326 opterr = 1; 327 while ((c = getopt(argc, argv, "acSs:hpBDrtiq?")) != -1) { 328 switch (c) { 329 case 'a': 330 all_sets_flag++; 331 break; 332 333 case 'c': 334 concise_flag++; 335 quiet_flg++; 336 break; 337 338 case 'S': 339 options |= PRINT_SETSTAT_ONLY; 340 break; 341 342 case 's': 343 sname = optarg; 344 set_flg++; 345 break; 346 347 case 'h': 348 usage(sp, 0); 349 break; 350 351 case 'p': 352 options |= PRINT_SHORT; 353 options &= ~PRINT_DEVID; 354 break; 355 356 case 't': 357 options |= PRINT_TIMES; 358 break; 359 360 case 'i': 361 inquire++; 362 break; 363 364 case 'B': 365 options |= PRINT_LARGEDEVICES; 366 break; 367 case 'D': 368 options |= PRINT_FN; 369 break; 370 case 'r': /* defunct option */ 371 break; 372 case 'q': 373 quiet_flg++; 374 break; 375 case '?': 376 if (optopt == '?') 377 usage(sp, 0); 378 /*FALLTHROUGH*/ 379 default: 380 usage(sp, 1); 381 break; 382 } 383 } 384 argc -= optind; 385 argv += optind; 386 387 if (all_sets_flag && set_flg) { 388 fprintf(stderr, gettext("metastat: " 389 "incompatible options: -a and -s\n")); 390 usage(sp, 1); 391 } 392 393 /* get set context */ 394 if ((sp = metasetname(sname, ep)) == NULL) { 395 mde_perror(ep, ""); 396 md_exit(sp, 1); 397 } 398 399 /* make sure that the mddb is not stale. Else print a warning */ 400 401 if (check_replica_state(sp, ep)) { 402 if (mdismddberror(ep, MDE_DB_STALE)) { 403 fprintf(stdout, gettext( 404 "****\nWARNING: Stale " 405 "state database replicas. Metastat output " 406 "may be inaccurate.\n****\n\n")); 407 } 408 } 409 410 /* if inquire is set. We probe first */ 411 if (inquire) { 412 if (geteuid() != 0) { 413 fprintf(stderr, gettext("metastat: -i " 414 "option requires super-user privilages\n")); 415 md_exit(sp, 1); 416 } 417 probe_all_devs(sp); 418 } 419 /* print debug stuff */ 420 if (((p = getenv("MD_DEBUG")) != NULL) && 421 (strstr(p, "STAT") != NULL)) { 422 options |= (PRINT_SETSTAT | PRINT_DEBUG | PRINT_TIMES); 423 } 424 425 if ((options & PRINT_SETSTAT) || (options & PRINT_SETSTAT_ONLY)) { 426 if (print_setstat(&sp, argv[0], stdout, options, ep)) { 427 mde_perror(ep, ""); 428 md_exit(sp, 1); 429 } 430 if (options & PRINT_SETSTAT_ONLY) 431 md_exit(sp, 0); 432 } 433 434 /* status all devices */ 435 if (argc == 0) { 436 if (all_sets_flag) { 437 print_all_sets(options, concise_flag, quiet_flg); 438 } else { 439 print_specific_set(sp, options, concise_flag, quiet_flg); 440 } 441 442 if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) { 443 mde_perror(ep, ""); 444 md_exit(sp, 1); 445 } 446 447 /* success */ 448 md_exit(sp, 0); 449 } 450 /* print named device types */ 451 while (devcnt < argc) { 452 char *uname = argv[devcnt]; 453 char *cname = NULL; 454 455 /* get the canonical name */ 456 cname = meta_name_getname(&sp, uname, META_DEVICE, ep); 457 if (cname == NULL) { 458 /* already printed the error */ 459 mdclrerror(ep); 460 eval = 1; 461 ++devcnt; 462 continue; 463 } 464 465 if (concise_flag) { 466 mdname_t *np; 467 468 np = metaname(&sp, cname, META_DEVICE, ep); 469 if (np == NULL) { 470 mde_perror(ep, ""); 471 mdclrerror(ep); 472 eval = 1; 473 } else { 474 print_concise_md(0, sp, np); 475 } 476 477 } else { 478 if (print_name(&sp, cname, &nlistp, NULL, stdout, options, 479 &meta_print_trans_msg, &lognlp, ep) != 0) { 480 mde_perror(ep, ""); 481 mdclrerror(ep); 482 eval = 1; 483 } 484 } 485 Free(cname); 486 ++devcnt; 487 } 488 489 /* print metadevice & relocation device id */ 490 if ((options & PRINT_DEVID) && (eval != 1) && !quiet_flg) { 491 devcnt = 0; 492 493 while (devcnt < argc) { 494 char *uname = argv[devcnt]; 495 char *cname = NULL; 496 497 /* get the canonical name */ 498 cname = meta_name_getname(&sp, uname, META_DEVICE, ep); 499 if (cname == NULL) { 500 mde_perror(ep, ""); 501 mdclrerror(ep); 502 ++devcnt; 503 continue; 504 } 505 506 /* hotspare pools */ 507 if (is_existing_hsp(sp, cname)) { 508 mdhspname_t *hspnamep; 509 md_hsp_t *hsp; 510 511 /* get hotsparepool */ 512 if ((hspnamep = metahspname(&sp, cname, 513 ep)) == NULL) 514 eval = 1; 515 516 if ((hsp = meta_get_hsp(sp, hspnamep, 517 ep)) == NULL) 518 eval = 1; 519 520 for (hsi = 0; 521 hsi < hsp->hotspares.hotspares_len; 522 hsi++) { 523 524 namep = hsp->hotspares. 525 hotspares_val[hsi].hsnamep; 526 527 if (!(options & 528 (PRINT_LARGEDEVICES | PRINT_FN))) { 529 /* meta_getdevs populates the */ 530 /* nlistp structure for use */ 531 if (meta_getdevs(sp, namep, 532 &nlistp, ep) != 0) 533 eval = 1; 534 } 535 536 } 537 538 } else { 539 540 /* get metadevice */ 541 if (((namep = metaname(&sp, cname, 542 META_DEVICE, ep)) == NULL) || 543 (metachkmeta(namep, ep) != 0)) 544 eval = 1; 545 546 if (!(options & 547 (PRINT_LARGEDEVICES | PRINT_FN))) { 548 /* meta_getdevs populates the */ 549 /* nlistp structure for use */ 550 if (meta_getdevs(sp, namep, &nlistp, ep) 551 != 0) 552 eval = 1; 553 } 554 } 555 Free(cname); 556 ++devcnt; 557 } 558 if (print_devid(sp, nlistp, stdout, ep) != 0) 559 eval = 1; 560 561 562 } 563 564 print_trans_msg(options, meta_print_trans_msg); 565 566 if (meta_smf_isonline(meta_smf_getmask(), ep) == 0) { 567 mde_perror(ep, ""); 568 md_exit(sp, 1); 569 } 570 571 /* return success */ 572 md_exit(sp, eval); 573 /*NOTREACHED*/ 574 return (eval); 575 } 576 577 static void 578 print_all_sets(mdprtopts_t options, int concise_flag, int quiet_flg) 579 { 580 uint_t max_sets; 581 md_error_t error = mdnullerror; 582 int i; 583 584 if ((max_sets = get_max_sets(&error)) == 0) { 585 return; 586 } 587 588 if (!mdisok(&error)) { 589 mdclrerror(&error); 590 return; 591 } 592 593 /* for each possible set number, see if we really have a diskset */ 594 for (i = 0; i < max_sets; i++) { 595 mdsetname_t *sp; 596 597 if ((sp = metasetnosetname(i, &error)) == NULL) { 598 if (!mdisok(&error) && 599 mdisrpcerror(&error, RPC_PROGNOTREGISTERED)) { 600 /* metad rpc program not registered - no metasets */ 601 break; 602 } 603 604 mdclrerror(&error); 605 continue; 606 } 607 mdclrerror(&error); 608 609 if (meta_check_ownership(sp, &error) == 0) { 610 /* we own the set, so we can print the metadevices */ 611 print_specific_set(sp, options, concise_flag, quiet_flg); 612 (void) printf("\n"); 613 } 614 615 metaflushsetname(sp); 616 } 617 } 618 619 static void 620 print_specific_set(mdsetname_t *sp, mdprtopts_t options, int concise_flag, 621 int quiet_flg) 622 { 623 md_error_t status = mdnullerror; 624 md_error_t *ep = &status; 625 int meta_print_trans_msg = 0; 626 627 /* check for ownership */ 628 assert(sp != NULL); 629 if (meta_check_ownership(sp, ep) != 0) { 630 mde_perror(ep, ""); 631 md_exit(sp, 1); 632 } 633 634 if (concise_flag) { 635 print_concise_diskset(sp); 636 637 } else { 638 mdnamelist_t *nlistp = NULL; 639 640 /* status devices */ 641 if (meta_print_all(sp, NULL, &nlistp, stdout, options, 642 &meta_print_trans_msg, ep) != 0) { 643 mde_perror(ep, ""); 644 md_exit(sp, 1); 645 } 646 647 /* print relocation device id on all dev's */ 648 if ((options & PRINT_DEVID) && !quiet_flg) { 649 /* 650 * Ignore return value from meta_getalldevs since 651 * it will return a failure if even one device cannot 652 * be found - which could occur in the case of device 653 * failure or a device being powered off during 654 * upgrade. Even if meta_getalldevs fails, the 655 * data in nlistp is still valid. 656 */ 657 if (!(options & (PRINT_LARGEDEVICES | PRINT_FN))) { 658 (void) meta_getalldevs(sp, &nlistp, 0, ep); 659 } 660 if (nlistp != NULL) { 661 if (print_devid(sp, nlistp, stdout, ep) != 0) { 662 mde_perror(ep, ""); 663 md_exit(sp, 1); 664 } 665 } 666 } 667 } 668 669 print_trans_msg(options, meta_print_trans_msg); 670 } 671 672 /* 673 * print_devid prints out cxtxdx and devid for devices passed in a 674 * mdnamelist_t structure 675 */ 676 static int 677 print_devid( 678 mdsetname_t *sp, 679 mdnamelist_t *nlp, 680 FILE *fp, 681 md_error_t *ep 682 ) 683 { 684 int retval = 0; 685 mdnamelist_t *onlp = NULL; 686 mddevid_t *ldevidp = NULL; 687 mddevid_t *nextp; 688 689 /* make a non-duplicate list of nlp */ 690 for (onlp = nlp; (onlp != NULL); onlp = onlp->next) { 691 meta_create_non_dup_list(onlp->namep, &ldevidp); 692 } 693 694 retval = meta_print_devid(sp, fp, ldevidp, ep); 695 696 /* cleanup */ 697 for (nextp = ldevidp; nextp != NULL; ldevidp = nextp) { 698 Free(ldevidp->ctdname); 699 nextp = ldevidp->next; 700 Free(ldevidp); 701 } 702 703 return (retval); 704 } 705 706 /* 707 * probedev issues ioctls for all the metadevices 708 */ 709 710 711 712 713 /* 714 * Failure return's a 1 715 */ 716 int 717 hotspare_ok(char *bname) 718 { 719 int fd; 720 char buf[512]; 721 722 if ((fd = open(bname, O_RDONLY)) < 0) 723 return (0); 724 if (read(fd, buf, sizeof (buf)) < 0) 725 return (0); 726 return (1); 727 } 728 729 void 730 delete_hotspares_impl(mdsetname_t *sp, mdhspname_t *hspnp, md_hsp_t *hspp) 731 { 732 md_hs_t *hsp; 733 uint_t hsi; 734 char *bname; 735 md_error_t e = mdnullerror; 736 int deleted_hs = 0; 737 738 for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) { 739 mdnamelist_t *nlp; 740 741 hsp = &hspp->hotspares.hotspares_val[hsi]; 742 bname = hsp->hsnamep->bname; 743 nlp = NULL; 744 metanamelist_append(&nlp, hsp->hsnamep); 745 /* print hotspare */ 746 if (hsp->state == HSS_AVAILABLE) { 747 if (hotspare_ok(bname)) 748 continue; 749 750 fprintf(stderr, 751 "NOTICE: Hotspare %s in %s has failed.\n" 752 "\tDeleting %s since it not in use\n\n", 753 bname, hspnp->hspname, bname); 754 755 if (meta_hs_delete(sp, hspnp, nlp, 0, &e) != NULL) { 756 mde_perror(&e, ""); 757 } else { 758 deleted_hs++; 759 } 760 } 761 } 762 } 763 764 765 766 /* 767 * Generic routine to issue ioctls 768 */ 769 770 void 771 md_setprobetest(md_probedev_t *iocp) 772 { 773 (void) strcpy(iocp->test_name, MD_PROBE_OPEN_T); 774 } 775 776 int 777 md_probe_ioctl(mdsetname_t *sp, mdnamelist_t *nlp, int ndevs, char *drvname) 778 { 779 mdnamelist_t *p; 780 mdname_t *np; 781 md_probedev_t probe_ioc, 782 *iocp; 783 int i, 784 retval = 0; 785 /* 786 * Allocate space for all the metadevices and fill in 787 * the minor numbers. 788 */ 789 790 memset(&probe_ioc, 0, sizeof (probe_ioc)); 791 iocp = &probe_ioc; 792 793 if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t))) 794 == 0) { 795 perror("md_probe_ioctl: calloc"); 796 return (-1); 797 } 798 799 MD_SETDRIVERNAME(iocp, drvname, sp->setno); 800 md_setprobetest(iocp); 801 802 iocp->nmdevs = ndevs; 803 804 for (p = nlp, i = 0; p; p = p->next, i++) { 805 np = p->namep; 806 ((minor_t *)(uintptr_t)iocp->mnum_list)[i] = 807 meta_getminor(np->dev); 808 } 809 810 811 if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0) 812 retval = -1; 813 return (retval); 814 } 815 /* 816 * 817 * - remove p from nlp list 818 * - put it on the toplp list. 819 * - update the p to the next element 820 */ 821 822 void 823 add_to_list(mdnamelist_t **curpp, mdnamelist_t **prevpp, mdnamelist_t **newlpp) 824 { 825 mdnamelist_t *p, *prevp, *nlp; 826 827 p = *curpp; 828 prevp = *prevpp; 829 nlp = *newlpp; 830 831 if (prevp == p) { 832 /* if first element reset prevp */ 833 prevp = p->next; 834 p->next = nlp; 835 nlp = p; 836 p = prevp; 837 } else { 838 prevp->next = p->next; 839 p->next = nlp; 840 nlp = p; 841 p = prevp->next; 842 } 843 *curpp = p; 844 *prevpp = prevp; 845 *newlpp = nlp; 846 } 847 /* 848 * Scans the given list of metadeivces and returns a list of top level 849 * metadevices. 850 * Note: The orignal list is not valid at the end and is set to NULL. 851 */ 852 853 int 854 get_toplevel_mds(mdsetname_t *sp, mdnamelist_t **lpp, 855 mdnamelist_t **top_pp) 856 { 857 mdnamelist_t *p, *prevp, *toplp; 858 int ntopmd; 859 md_common_t *mdp; 860 md_error_t e = mdnullerror; 861 862 ntopmd = 0; 863 prevp = p = *lpp; 864 toplp = NULL; 865 866 while (p) { 867 if ((mdp = meta_get_unit(sp, p->namep, &e)) == NULL) { 868 prevp = p; 869 p = p->next; 870 continue; 871 } 872 873 if (mdp->parent == MD_NO_PARENT) { 874 /* increment the top level md count. */ 875 ntopmd++; 876 add_to_list(&p, &prevp, &toplp); 877 } else { 878 prevp = p; 879 p = p->next; 880 } 881 } 882 *lpp = NULL; 883 *top_pp = toplp; 884 885 return (ntopmd); 886 } 887 888 int 889 get_namelist(mdnamelist_t **transdevlist, mdnamelist_t **devlist, 890 char *dev_type) 891 { 892 mdnamelist_t *np, *prevp; 893 md_error_t e = mdnullerror; 894 char *type_name; 895 int i = 0; 896 897 prevp = np = *transdevlist; 898 while (np) { 899 if ((type_name = metagetmiscname(np->namep, &e)) == NULL) { 900 *devlist = NULL; 901 return (-1); 902 } 903 if (strcmp(type_name, dev_type) == 0) { 904 /* move it to the devlist */ 905 add_to_list(&np, &prevp, devlist); 906 i++; 907 } else { 908 prevp = np; 909 np = np->next; 910 } 911 } 912 return (i); 913 } 914 915 916 mdnamelist_t * 917 create_nlp(mdsetname_t *sp) 918 { 919 mdnamelist_t *np; 920 md_error_t e = mdnullerror; 921 922 if (np = (mdnamelist_t *)malloc(sizeof (mdnamelist_t))) { 923 np->next = NULL; 924 return (np); 925 } else { 926 /* error condition below */ 927 mde_perror(&e, "create_nlp: malloc failed\n"); 928 md_exit(sp, 1); 929 } 930 return (0); 931 } 932 933 /* 934 * Create a list of metadevices associated with trans. top_pp points to 935 * this list. The number of components in the list are also returned. 936 */ 937 int 938 create_trans_compslist(mdsetname_t *sp, mdnamelist_t **lpp, 939 mdnamelist_t **top_pp) 940 { 941 mdnamelist_t *p, *tailp, *toplp, *newlp; 942 int ntoptrans; 943 md_error_t e = mdnullerror; 944 md_trans_t *tp; 945 946 ntoptrans = 0; 947 p = *lpp; 948 tailp = toplp = NULL; 949 /* 950 * Scan the current list of trans devices. From that 951 * extract all the lower level metadevices and put them on 952 * toplp list. 953 */ 954 955 while (p) { 956 if (tp = meta_get_trans(sp, p->namep, &e)) { 957 /* 958 * Check the master and log devices to see if they 959 * are metadevices 960 */ 961 if (metaismeta(tp->masternamep)) { 962 /* get a mdnamelist_t. */ 963 newlp = create_nlp(sp); 964 newlp->namep = tp->masternamep; 965 if (toplp == NULL) { 966 toplp = tailp = newlp; 967 } else { 968 tailp->next = newlp; 969 tailp = newlp; 970 } 971 ntoptrans++; 972 } 973 974 if (tp->lognamep && metaismeta(tp->lognamep)) { 975 newlp = create_nlp(sp); 976 newlp->namep = tp->lognamep; 977 if (toplp == NULL) { 978 toplp = tailp = newlp; 979 } else { 980 tailp->next = newlp; 981 tailp = newlp; 982 } 983 ntoptrans++; 984 } 985 p = p->next; 986 } 987 } 988 *top_pp = toplp; 989 return (ntoptrans); 990 } 991 992 void 993 probe_mirror_devs(mdsetname_t *sp) 994 { 995 mdnamelist_t *nlp, *toplp; 996 int cnt; 997 md_error_t e = mdnullerror; 998 999 nlp = toplp = NULL; 1000 1001 if (meta_get_mirror_names(sp, &nlp, 0, &e) > 0) { 1002 /* 1003 * We have some mirrors to probe 1004 * get a list of top-level mirrors 1005 */ 1006 1007 cnt = get_toplevel_mds(sp, &nlp, &toplp); 1008 if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_MIRROR) < 0)) 1009 perror("MD_IOCPROBE_DEV"); 1010 } 1011 metafreenamelist(nlp); 1012 metafreenamelist(toplp); 1013 1014 } 1015 1016 void 1017 probe_raid_devs(mdsetname_t *sp) 1018 { 1019 mdnamelist_t *nlp, *toplp; 1020 int cnt; 1021 md_error_t e = mdnullerror; 1022 1023 nlp = toplp = NULL; 1024 1025 if (meta_get_raid_names(sp, &nlp, 0, &e) > 0) { 1026 /* 1027 * We have some mirrors to probe 1028 * get a list of top-level mirrors 1029 */ 1030 1031 cnt = get_toplevel_mds(sp, &nlp, &toplp); 1032 1033 if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_RAID) < 0)) 1034 perror("MD_IOCPROBE_DEV"); 1035 } 1036 metafreenamelist(nlp); 1037 metafreenamelist(toplp); 1038 } 1039 1040 /* 1041 * Trans probes are diffenent. -- so whats new. 1042 * we separate out the master and log device and then issue the 1043 * probe calls. 1044 * Since the underlying device could be disk, stripe, RAID or miror, 1045 * we have to sort them out and then call the ioctl for each. 1046 */ 1047 1048 void 1049 probe_trans_devs(mdsetname_t *sp) 1050 { 1051 mdnamelist_t *nlp, *toplp; 1052 mdnamelist_t *trans_raidlp, *trans_mmlp, *trans_stripelp; 1053 int cnt; 1054 md_error_t e = mdnullerror; 1055 1056 nlp = toplp = NULL; 1057 trans_raidlp = trans_mmlp = trans_stripelp = NULL; 1058 1059 if (meta_get_trans_names(sp, &nlp, 0, &e) > 0) { 1060 /* 1061 * get a list of master and log metadevices. 1062 */ 1063 1064 cnt = create_trans_compslist(sp, &nlp, &toplp); 1065 1066 /* underlying RAID-5 components */ 1067 1068 cnt = get_namelist(&toplp, &trans_raidlp, MD_RAID); 1069 if ((cnt > 0) && (md_probe_ioctl(sp, trans_raidlp, cnt, 1070 MD_RAID) < 0)) 1071 perror("MD_IOCPROBE_DEV"); 1072 1073 metafreenamelist(trans_raidlp); 1074 1075 /* underlying mirror components */ 1076 1077 cnt = get_namelist(&toplp, &trans_mmlp, MD_MIRROR); 1078 1079 if ((cnt > 0) && (md_probe_ioctl(sp, trans_mmlp, cnt, 1080 MD_MIRROR) < 0)) 1081 perror("MD_IOCPROBE_DEV"); 1082 1083 metafreenamelist(trans_mmlp); 1084 1085 /* underlying stripe components */ 1086 1087 cnt = get_namelist(&toplp, &trans_stripelp, MD_STRIPE); 1088 if ((cnt > 0) && (md_probe_ioctl(sp, trans_stripelp, cnt, 1089 MD_STRIPE) < 0)) 1090 perror("MD_IOCPROBE_DEV"); 1091 metafreenamelist(trans_stripelp); 1092 metafreenamelist(nlp); 1093 } 1094 } 1095 1096 /* 1097 * probe hot spares. This is differs from other approaches since 1098 * there are no read/write routines through md. We check at the physical 1099 * component level and then delete it if its bad. 1100 */ 1101 1102 void 1103 probe_hotspare_devs(mdsetname_t *sp) 1104 { 1105 mdhspnamelist_t *hspnlp = NULL; 1106 int cnt; 1107 mdhspnamelist_t *p; 1108 md_hsp_t *hspp; 1109 md_error_t e = mdnullerror; 1110 1111 if ((cnt = meta_get_hsp_names(sp, &hspnlp, 0, &e)) < 0) { 1112 mderror(&e, MDE_UNIT_NOT_FOUND, NULL); 1113 return; 1114 } else if (cnt == 0) { 1115 mderror(&e, MDE_NO_HSPS, NULL); 1116 return; 1117 } 1118 for (p = hspnlp; (p != NULL); p = p->next) { 1119 mdhspname_t *hspnp = p->hspnamep; 1120 1121 1122 if ((hspp = meta_get_hsp(sp, hspnp, &e)) == NULL) 1123 continue; 1124 1125 if (hspp->hotspares.hotspares_len != 0) { 1126 delete_hotspares_impl(sp, hspnp, hspp); 1127 } 1128 } 1129 metafreehspnamelist(hspnlp); 1130 } 1131 1132 static void 1133 probe_all_devs(mdsetname_t *sp) 1134 { 1135 probe_hotspare_devs(sp); 1136 probe_mirror_devs(sp); 1137 probe_raid_devs(sp); 1138 probe_trans_devs(sp); 1139 } 1140 1141 /* 1142 * The following functions are used to print the concise output 1143 * of the metastat coommand (-c option). 1144 * 1145 * Normally the output for metastat is performed within libmeta via 1146 * the *_report functions within each of the metadevice specific files in 1147 * libmeta. However, it is usually bad architecture for a library to 1148 * perform output since there are so many different ways that an application 1149 * can choose to do output (e.g. GUI, CLI, CIM, SNMP, etc.). So, for the 1150 * concise output option we have moved the CLI output to the metastat 1151 * code and just use libmeta as the source of data to be printed. 1152 * 1153 * This function gets all of the different top-level metadevices in the set 1154 * and prints them. It calls the print_concise_md() function to recursively 1155 * print the metadevices that underly the top-level metadevices. It does 1156 * special handling for soft partitions so that all of the SPs on the 1157 * same underlying device are grouped and then that underlying device 1158 * is only printed once. 1159 */ 1160 static void 1161 print_concise_diskset(mdsetname_t *sp) 1162 { 1163 md_error_t error = mdnullerror; 1164 mdnamelist_t *nl = NULL; 1165 mdhspnamelist_t *hsp_list = NULL; 1166 1167 /* 1168 * We do extra handling for soft parts since we want to find 1169 * all of the SPs on the same underlying device, group them and 1170 * print them together before printing the underlying device just 1171 * once. This logic doesn't apply to any other metadevice type. 1172 */ 1173 if (meta_get_sp_names(sp, &nl, 0, &error) >= 0) { 1174 mdnamelist_t *nlp; 1175 /* keep track of the softparts on the same underlying device */ 1176 struct sp_base_list *base_list = NULL; 1177 1178 for (nlp = nl; nlp != NULL; nlp = nlp->next) { 1179 mdname_t *mdn; 1180 md_sp_t *soft_part; 1181 mdnamelist_t *tnlp; 1182 1183 mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error); 1184 mdclrerror(&error); 1185 if (mdn == NULL) { 1186 print_concise_entry(0, nlp->namep->cname, 0, 'p'); 1187 printf("\n"); 1188 continue; 1189 } 1190 1191 soft_part = meta_get_sp_common(sp, mdn, 1, &error); 1192 mdclrerror(&error); 1193 1194 if (soft_part == NULL || 1195 MD_HAS_PARENT(soft_part->common.parent) || 1196 sp_done(soft_part, base_list)) 1197 continue; 1198 1199 /* print this soft part */ 1200 print_concise_entry(0, soft_part->common.namep->cname, 1201 soft_part->common.size, 'p'); 1202 (void) printf(" %s\n", soft_part->compnamep->cname); 1203 1204 /* keep track of the underlying device of this soft part */ 1205 base_list = sp_add_done(soft_part, base_list); 1206 1207 /* 1208 * now print all of the other soft parts on the same 1209 * underlying device 1210 */ 1211 for (tnlp = nlp->next; tnlp != NULL; tnlp = tnlp->next) { 1212 md_sp_t *part; 1213 1214 mdn = metaname(&sp, tnlp->namep->cname, 1215 META_DEVICE, &error); 1216 1217 mdclrerror(&error); 1218 if (mdn == NULL) 1219 continue; 1220 1221 part = meta_get_sp_common(sp, mdn, 1, &error); 1222 mdclrerror(&error); 1223 1224 if (part == NULL || MD_HAS_PARENT(part->common.parent) || 1225 ! sp_match(part, base_list)) 1226 continue; 1227 1228 /* on the same base so print this soft part */ 1229 print_concise_entry(0, part->common.namep->cname, 1230 part->common.size, 'p'); 1231 (void) printf(" %s\n", part->compnamep->cname); 1232 } 1233 1234 /* 1235 * print the common metadevice hierarchy under these soft parts 1236 */ 1237 print_concise_md(META_INDENT, sp, soft_part->compnamep); 1238 } 1239 1240 free_names(&nl); 1241 sp_free_list(base_list); 1242 } 1243 mdclrerror(&error); 1244 1245 if (meta_get_trans_names(sp, &nl, 0, &error) >= 0) 1246 print_concise_namelist(sp, &nl, 't'); 1247 mdclrerror(&error); 1248 1249 if (meta_get_mirror_names(sp, &nl, 0, &error) >= 0) 1250 print_concise_namelist(sp, &nl, 'm'); 1251 mdclrerror(&error); 1252 1253 if (meta_get_raid_names(sp, &nl, 0, &error) >= 0) 1254 print_concise_namelist(sp, &nl, 'r'); 1255 mdclrerror(&error); 1256 1257 if (meta_get_stripe_names(sp, &nl, 0, &error) >= 0) 1258 print_concise_namelist(sp, &nl, 's'); 1259 mdclrerror(&error); 1260 1261 if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) { 1262 mdhspnamelist_t *nlp; 1263 1264 for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) { 1265 md_hsp_t *hsp; 1266 1267 print_concise_entry(0, nlp->hspnamep->hspname, 0, 'h'); 1268 1269 hsp = meta_get_hsp_common(sp, nlp->hspnamep, 1, &error); 1270 mdclrerror(&error); 1271 if (hsp != NULL) { 1272 int i; 1273 1274 for (i = 0; i < hsp->hotspares.hotspares_len; i++) { 1275 md_hs_t *hs; 1276 char *state; 1277 1278 hs = &hsp->hotspares.hotspares_val[i]; 1279 1280 (void) printf(" %s", hs->hsnamep->cname); 1281 1282 state = get_hs_state(hs); 1283 if (state != NULL) 1284 (void) printf(" (%s)", state); 1285 } 1286 } 1287 1288 (void) printf("\n"); 1289 } 1290 1291 metafreehspnamelist(hsp_list); 1292 } 1293 } 1294 1295 /* 1296 * Print the top-level metadevices in the name list for concise output. 1297 */ 1298 static void 1299 print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl, char mtype) 1300 { 1301 mdnamelist_t *nlp; 1302 md_error_t error = mdnullerror; 1303 1304 for (nlp = *nl; nlp != NULL; nlp = nlp->next) { 1305 mdname_t *mdn; 1306 md_common_t *u; 1307 1308 mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error); 1309 mdclrerror(&error); 1310 if (mdn == NULL) { 1311 print_concise_entry(0, nlp->namep->cname, 0, mtype); 1312 printf("\n"); 1313 continue; 1314 } 1315 1316 u = get_concise_unit(sp, mdn, &error); 1317 mdclrerror(&error); 1318 1319 if (u != NULL && !MD_HAS_PARENT(u->parent)) 1320 print_concise_md(0, sp, mdn); 1321 } 1322 1323 free_names(nl); 1324 } 1325 1326 /* 1327 * Concise mirror output. 1328 */ 1329 static void 1330 print_concise_mirror(int indent, mdsetname_t *sp, md_mirror_t *mirror) 1331 { 1332 md_error_t error = mdnullerror; 1333 int i; 1334 md_status_t status = mirror->common.state; 1335 1336 if (mirror == NULL) 1337 return; 1338 1339 print_concise_entry(indent, mirror->common.namep->cname, 1340 mirror->common.size, 'm'); 1341 1342 for (i = 0; i < NMIRROR; i++) { 1343 uint_t tstate = 0; 1344 char *state; 1345 1346 if (mirror->submirrors[i].submirnamep == NULL) 1347 continue; 1348 (void) printf(" %s", mirror->submirrors[i].submirnamep->cname); 1349 1350 if (mirror->submirrors[i].state & SMS_OFFLINE) { 1351 (void) printf(gettext(" (offline)")); 1352 continue; 1353 } 1354 1355 if (metaismeta(mirror->submirrors[i].submirnamep)) 1356 (void) meta_get_tstate(mirror->submirrors[i].submirnamep->dev, 1357 &tstate, &error); 1358 1359 state = get_sm_state(mirror, i, status, tstate); 1360 if (state != NULL) 1361 (void) printf(" (%s)", state); 1362 } 1363 1364 (void) printf("\n"); 1365 1366 indent += META_INDENT; 1367 for (i = 0; i < NMIRROR; i++) { 1368 if (mirror->submirrors[i].submirnamep == NULL) 1369 continue; 1370 1371 print_concise_md(indent, sp, mirror->submirrors[i].submirnamep); 1372 } 1373 } 1374 1375 /* 1376 * Concise raid output. 1377 */ 1378 static void 1379 print_concise_raid(int indent, mdsetname_t *sp, md_raid_t *raid) 1380 { 1381 md_error_t error = mdnullerror; 1382 int i; 1383 uint_t tstate = 0; 1384 1385 if (raid == NULL) 1386 return; 1387 1388 print_concise_entry(indent, raid->common.namep->cname, 1389 raid->common.size, 'r'); 1390 1391 if (metaismeta(raid->common.namep)) 1392 (void) meta_get_tstate(raid->common.namep->dev, &tstate, &error); 1393 1394 for (i = 0; i < raid->cols.cols_len; i++) { 1395 md_raidcol_t *colp = &raid->cols.cols_val[i]; 1396 mdname_t *namep = ((colp->hsnamep != NULL) ? 1397 colp->hsnamep : colp->colnamep); 1398 char *hsname = ((colp->hsnamep != NULL) ? 1399 colp->hsnamep->cname : NULL); 1400 char *col_state = NULL; 1401 1402 (void) printf(" %s", colp->colnamep->cname); 1403 1404 if (metaismeta(namep)) { 1405 uint_t tstate = 0; 1406 1407 (void) meta_get_tstate(namep->dev, &tstate, &error); 1408 col_state = get_raid_col_state(colp, tstate); 1409 1410 } else { 1411 if (tstate != 0) 1412 col_state = "-"; 1413 else 1414 col_state = get_raid_col_state(colp, tstate); 1415 } 1416 1417 if (col_state != NULL) { 1418 if (hsname != NULL) 1419 (void) printf(" (%s-%s)", col_state, hsname); 1420 else 1421 (void) printf(" (%s)", col_state); 1422 1423 } else if (hsname != NULL) { 1424 (void) printf(gettext(" (spared-%s)"), hsname); 1425 } 1426 } 1427 1428 (void) printf("\n"); 1429 1430 indent += META_INDENT; 1431 for (i = 0; i < raid->cols.cols_len; i++) { 1432 print_concise_md(indent, sp, raid->cols.cols_val[i].colnamep); 1433 } 1434 } 1435 1436 /* 1437 * Concise stripe output. 1438 */ 1439 static void 1440 print_concise_stripe(int indent, mdsetname_t *sp, md_stripe_t *stripe) 1441 { 1442 md_error_t error = mdnullerror; 1443 int i; 1444 uint_t top_tstate = 0; 1445 1446 if (stripe == NULL) 1447 return; 1448 1449 print_concise_entry(indent, stripe->common.namep->cname, 1450 stripe->common.size, 's'); 1451 1452 if (metaismeta(stripe->common.namep)) 1453 (void) meta_get_tstate(stripe->common.namep->dev, &top_tstate, 1454 &error); 1455 mdclrerror(&error); 1456 1457 for (i = 0; i < stripe->rows.rows_len; i++) { 1458 md_row_t *rowp; 1459 int j; 1460 1461 rowp = &stripe->rows.rows_val[i]; 1462 1463 for (j = 0; j < rowp->comps.comps_len; j++) { 1464 md_comp_t *comp; 1465 uint_t tstate = 0; 1466 char *comp_state = NULL; 1467 char *hsname; 1468 1469 comp = &rowp->comps.comps_val[j]; 1470 (void) printf(" %s", comp->compnamep->cname); 1471 1472 if (metaismeta(comp->compnamep)) { 1473 uint_t tstate = 0; 1474 (void) meta_get_tstate(comp->compnamep->dev, &tstate, 1475 &error); 1476 comp_state = get_stripe_state(comp, tstate); 1477 } else { 1478 if (top_tstate != 0) 1479 comp_state = "-"; 1480 else 1481 comp_state = get_stripe_state(comp, tstate); 1482 } 1483 1484 hsname = ((comp->hsnamep != NULL) ? 1485 comp->hsnamep->cname : NULL); 1486 1487 if (comp_state != NULL) { 1488 if (hsname != NULL) 1489 (void) printf(" (%s-%s)", comp_state, hsname); 1490 else 1491 (void) printf(" (%s)", comp_state); 1492 1493 } else if (hsname != NULL) { 1494 (void) printf(gettext(" (spared-%s)"), hsname); 1495 } 1496 } 1497 } 1498 1499 (void) printf("\n"); 1500 1501 indent += META_INDENT; 1502 for (i = 0; i < stripe->rows.rows_len; i++) { 1503 md_row_t *rowp; 1504 int j; 1505 1506 rowp = &stripe->rows.rows_val[i]; 1507 1508 for (j = 0; j < rowp->comps.comps_len; j++) { 1509 print_concise_md(indent, sp, 1510 rowp->comps.comps_val[j].compnamep); 1511 } 1512 } 1513 } 1514 1515 /* 1516 * Concise soft partition output. 1517 */ 1518 static void 1519 print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part) 1520 { 1521 if (part == NULL) 1522 return; 1523 1524 print_concise_entry(indent, part->common.namep->cname, 1525 part->common.size, 'p'); 1526 1527 (void) printf(" %s\n", part->compnamep->cname); 1528 1529 print_concise_md(indent + META_INDENT, sp, part->compnamep); 1530 } 1531 1532 /* 1533 * Concise trans output. 1534 */ 1535 static void 1536 print_concise_trans(int indent, mdsetname_t *sp, md_trans_t *trans) 1537 { 1538 if (trans == NULL) 1539 return; 1540 1541 print_concise_entry(indent, trans->common.namep->cname, 1542 trans->common.size, 't'); 1543 1544 if (trans->masternamep != NULL) 1545 (void) printf(" %s", trans->masternamep->cname); 1546 1547 if (trans->lognamep != NULL) 1548 (void) printf(" %s", trans->lognamep->cname); 1549 1550 (void) printf("\n"); 1551 1552 indent += META_INDENT; 1553 1554 print_concise_md(indent, sp, trans->masternamep); 1555 1556 print_concise_md(indent, sp, trans->lognamep); 1557 } 1558 1559 /* 1560 * Recursive function for concise metadevice nested output. 1561 */ 1562 static void 1563 print_concise_md(int indent, mdsetname_t *sp, mdname_t *np) 1564 { 1565 md_error_t error = mdnullerror; 1566 md_unit_t *u; 1567 md_mirror_t *mirror; 1568 md_raid_t *raid; 1569 md_sp_t *soft_part; 1570 md_stripe_t *stripe; 1571 md_trans_t *trans; 1572 1573 if (np == NULL || !metaismeta(np)) 1574 return; 1575 1576 if ((u = meta_get_mdunit(sp, np, &error)) == NULL) 1577 return; 1578 1579 switch (u->c.un_type) { 1580 case MD_DEVICE: 1581 stripe = meta_get_stripe_common(sp, np, 1, &error); 1582 print_concise_stripe(indent, sp, stripe); 1583 break; 1584 1585 case MD_METAMIRROR: 1586 mirror = meta_get_mirror(sp, np, &error); 1587 print_concise_mirror(indent, sp, mirror); 1588 break; 1589 1590 case MD_METATRANS: 1591 trans = meta_get_trans_common(sp, np, 1, &error); 1592 print_concise_trans(indent, sp, trans); 1593 break; 1594 1595 case MD_METARAID: 1596 raid = meta_get_raid_common(sp, np, 1, &error); 1597 print_concise_raid(indent, sp, raid); 1598 break; 1599 1600 case MD_METASP: 1601 soft_part = meta_get_sp_common(sp, np, 1, &error); 1602 print_concise_sp(indent, sp, soft_part); 1603 break; 1604 1605 default: 1606 return; 1607 } 1608 } 1609 1610 /* 1611 * Given a name get the unit for use in concise output. We use the *_common 1612 * routines in libmeta which allow us to specify the "fast" flag, thereby 1613 * avoiding the DKIOCGGEOM ioctl that normally happens. 1614 */ 1615 static md_common_t * 1616 get_concise_unit(mdsetname_t *sp, mdname_t *np, md_error_t *ep) 1617 { 1618 char *miscname; 1619 1620 /* short circuit */ 1621 if (np->drivenamep->unitp != NULL) 1622 return (np->drivenamep->unitp); 1623 if (metachkmeta(np, ep) != 0) 1624 return (NULL); 1625 1626 /* dispatch */ 1627 if ((miscname = metagetmiscname(np, ep)) == NULL) 1628 return (NULL); 1629 else if (strcmp(miscname, MD_STRIPE) == 0) 1630 return ((md_common_t *)meta_get_stripe_common(sp, np, 1, ep)); 1631 else if (strcmp(miscname, MD_MIRROR) == 0) 1632 return ((md_common_t *)meta_get_mirror(sp, np, ep)); 1633 else if (strcmp(miscname, MD_TRANS) == 0) 1634 return ((md_common_t *)meta_get_trans_common(sp, np, 1, ep)); 1635 else if (strcmp(miscname, MD_RAID) == 0) 1636 return ((md_common_t *)meta_get_raid_common(sp, np, 1, ep)); 1637 else if (strcmp(miscname, MD_SP) == 0) 1638 return ((md_common_t *)meta_get_sp_common(sp, np, 1, ep)); 1639 else { 1640 (void) mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(np->dev), 1641 np->cname); 1642 return (NULL); 1643 } 1644 } 1645 1646 static void 1647 free_names(mdnamelist_t **nlp) 1648 { 1649 mdnamelist_t *p; 1650 1651 for (p = *nlp; p != NULL; p = p->next) { 1652 meta_invalidate_name(p->namep); 1653 p->namep = NULL; 1654 } 1655 metafreenamelist(*nlp); 1656 *nlp = NULL; 1657 } 1658 1659 /* 1660 * Submirror state for concise output. 1661 */ 1662 static char * 1663 get_sm_state(md_mirror_t *mirror, int i, md_status_t mirror_status, 1664 uint_t tstate) 1665 { 1666 sm_state_t state = mirror->submirrors[i].state; 1667 uint_t is_target = 1668 mirror->submirrors[i].flags & MD_SM_RESYNC_TARGET; 1669 1670 /* 1671 * Only return Unavailable if there is no flagged error on the 1672 * submirror. If the mirror has received any writes since the submirror 1673 * went into Unavailable state a resync is required. To alert the 1674 * administrator to this we return a 'Needs maintenance' message. 1675 */ 1676 if ((tstate != 0) && (state & SMS_RUNNING)) 1677 return (gettext("unavail")); 1678 1679 /* all is well */ 1680 if (state & SMS_RUNNING) { 1681 if (!(mirror_status & MD_UN_OPT_NOT_DONE) || 1682 ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target)) 1683 return (NULL); 1684 } 1685 1686 /* resyncing, needs repair */ 1687 if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC | 1688 SMS_OFFLINE_RESYNC)) || (mirror_status & MD_UN_OPT_NOT_DONE)) { 1689 static char buf[MAXPATHLEN]; 1690 1691 if (mirror_status & MD_UN_RESYNC_ACTIVE) { 1692 1693 if (mirror->common.revision & MD_64BIT_META_DEV) { 1694 (void) snprintf(buf, sizeof (buf), 1695 gettext("resync-%2d.%1d%%"), 1696 mirror->percent_done / 10, 1697 mirror->percent_done % 10); 1698 } else { 1699 (void) snprintf(buf, sizeof (buf), 1700 gettext("resync-%d%%"), mirror->percent_done); 1701 } 1702 return (buf); 1703 } 1704 return (gettext("maint")); 1705 } 1706 1707 /* needs repair */ 1708 if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE)) 1709 return (gettext("maint")); 1710 1711 /* unknown */ 1712 return (gettext("unknown")); 1713 } 1714 1715 /* 1716 * Raid component state for concise output. 1717 */ 1718 static char * 1719 get_raid_col_state(md_raidcol_t *colp, uint_t tstate) 1720 { 1721 if (tstate != 0) 1722 return (gettext("unavail")); 1723 1724 return (meta_get_raid_col_state(colp->state)); 1725 } 1726 1727 /* 1728 * Stripe state for concise output. 1729 */ 1730 static char * 1731 get_stripe_state(md_comp_t *mdcp, uint_t tstate) 1732 { 1733 comp_state_t state = mdcp->state; 1734 1735 if (tstate != 0) 1736 return ("unavail"); 1737 1738 return (meta_get_stripe_state(state)); 1739 } 1740 1741 /* 1742 * Hostspare state for concise output. 1743 */ 1744 static char * 1745 get_hs_state(md_hs_t *hsp) 1746 { 1747 hotspare_states_t state = hsp->state; 1748 1749 return (meta_get_hs_state(state)); 1750 } 1751 1752 1753 /* 1754 * Keep track of printed soft partitions for concise output. 1755 */ 1756 static struct sp_base_list * 1757 sp_add_done(md_sp_t *part, struct sp_base_list *lp) 1758 { 1759 struct sp_base_list *n; 1760 1761 n = (struct sp_base_list *)malloc(sizeof (struct sp_base_list)); 1762 if (n == NULL) 1763 return (lp); 1764 1765 if ((n->base = strdup(part->compnamep->cname)) == NULL) { 1766 free(n); 1767 return (lp); 1768 } 1769 1770 n->next = lp; 1771 1772 return (n); 1773 } 1774 1775 /* 1776 * Keep track of printed soft partitions for concise output. 1777 */ 1778 static int 1779 sp_done(md_sp_t *part, struct sp_base_list *lp) 1780 { 1781 for (; lp != NULL; lp = lp->next) { 1782 if (strcmp(lp->base, part->compnamep->cname) == 0) 1783 return (1); 1784 } 1785 1786 return (0); 1787 } 1788 1789 /* 1790 * Check the first element for a match. 1791 */ 1792 static int 1793 sp_match(md_sp_t *part, struct sp_base_list *lp) 1794 { 1795 if (lp != NULL && strcmp(lp->base, part->compnamep->cname) == 0) 1796 return (1); 1797 1798 return (0); 1799 } 1800 1801 /* 1802 * Free memory used for soft partition printed status in concise output. 1803 */ 1804 static void 1805 sp_free_list(struct sp_base_list *lp) 1806 { 1807 struct sp_base_list *n; 1808 1809 for (; lp != NULL; lp = n) { 1810 n = lp->next; 1811 free(lp->base); 1812 free(lp); 1813 } 1814 } 1815