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