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