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