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