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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 #include <stdio.h> 28 #include <errno.h> 29 #include <unistd.h> 30 #include <string.h> 31 32 #include <meta.h> 33 #include <sys/lvm/md_mddb.h> 34 #include <sdssc.h> 35 36 /* 37 * print metadevice status 38 */ 39 40 41 #define MD_PROBE_OPEN_T "probe open test" 42 43 /* used to keep track of the softparts on the same underlying device */ 44 struct sp_base_list { 45 struct sp_base_list *next; 46 char *base; 47 }; 48 49 /* 50 * Function prototypes 51 */ 52 static void probe_all_devs(mdsetname_t *sp); 53 54 static int print_devid(mdsetname_t *sp, mdnamelist_t *nlp, FILE *fp, 55 md_error_t *ep); 56 57 static md_common_t *get_concise_unit(mdsetname_t *sp, mdname_t *np, 58 md_error_t *ep); 59 static void print_all_sets(mdprtopts_t options, int concise_flag, 60 int quiet_flg); 61 static void print_specific_set(mdsetname_t *sp, mdprtopts_t options, 62 int concise_flag, int quiet_flg); 63 static void print_concise_diskset(mdsetname_t *sp); 64 static void print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl, 65 char mtype); 66 static void print_concise_md(int indent, mdsetname_t *sp, mdname_t *np); 67 static void print_concise_mirror(int indent, mdsetname_t *sp, 68 md_mirror_t *mirror); 69 static void print_concise_raid(int indent, mdsetname_t *sp, 70 md_raid_t *raid); 71 static void print_concise_stripe(int indent, mdsetname_t *sp, 72 md_stripe_t *stripe); 73 static void print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part); 74 static void print_concise_trans(int indent, mdsetname_t *sp, 75 md_trans_t *trans); 76 static void free_names(mdnamelist_t **nlp); 77 static char *get_sm_state(md_mirror_t *mirror, int i, 78 md_status_t mirror_status, uint_t tstate); 79 static char *get_raid_col_state(md_raidcol_t *colp, uint_t tstate); 80 static char *get_stripe_state(md_comp_t *mdcp, uint_t tstate); 81 static char *get_hs_state(md_hs_t *hsp); 82 static struct sp_base_list *sp_add_done(md_sp_t *part, struct sp_base_list *lp); 83 static int sp_done(md_sp_t *part, struct sp_base_list *lp); 84 static int sp_match(md_sp_t *part, struct sp_base_list *lp); 85 static void sp_free_list(struct sp_base_list *lp); 86 87 88 /* 89 * print named hotspare pool or metadevice 90 */ 91 static int 92 print_name( 93 mdsetname_t **spp, 94 char *uname, 95 mdnamelist_t **nlistpp, 96 char *fname, 97 FILE *fp, 98 mdprtopts_t options, 99 int *meta_print_trans_msgp, 100 mdnamelist_t **lognlpp, 101 md_error_t *ep 102 ) 103 { 104 mdname_t *namep; 105 char *miscname; 106 107 /* recurse */ 108 options |= PRINT_SUBDEVS; 109 110 /* hotspare pool */ 111 if (is_existing_hsp(*spp, uname)) { 112 mdhspname_t *hspnamep; 113 114 /* get hotsparepool */ 115 if ((hspnamep = metahspname(spp, uname, ep)) == NULL) 116 return (-1); 117 118 /* check for ownership */ 119 assert(*spp != NULL); 120 if (meta_check_ownership(*spp, ep) != 0) 121 return (-1); 122 123 /* print hotspare pool */ 124 return (meta_hsp_print(*spp, hspnamep, lognlpp, fname, fp, 125 options, ep)); 126 } 127 128 /* get metadevice */ 129 if (((namep = metaname(spp, uname, META_DEVICE, ep)) == NULL) || 130 (metachkmeta(namep, ep) != 0)) 131 return (-1); 132 133 /* check for ownership */ 134 assert(*spp != NULL); 135 if (meta_check_ownership(*spp, ep) != 0) 136 return (-1); 137 138 if ((miscname = metagetmiscname(namep, ep)) != NULL) { 139 if (strcmp(miscname, MD_TRANS) == 0) { 140 *meta_print_trans_msgp = 1; 141 } 142 } 143 144 /* print metadevice */ 145 return (meta_print_name(*spp, namep, nlistpp, fname, fp, options, 146 lognlpp, ep)); 147 } 148 149 /* 150 * print the per set flags 151 */ 152 /*ARGSUSED*/ 153 static int 154 print_setstat( 155 mdsetname_t **spp, 156 char *fname, 157 FILE *fp, 158 mdprtopts_t options, 159 md_error_t *ep 160 ) 161 { 162 int rval = -1; 163 char *cname = NULL; 164 char *cp = NULL; 165 md_gs_stat_parm_t gsp; 166 167 168 if (fname != NULL && strchr(fname, '/') != NULL) { 169 /* get the canonical name */ 170 cname = meta_name_getname(spp, fname, META_DEVICE, ep); 171 if (cname == NULL) 172 return (-1); 173 Free(cname); 174 } 175 176 if ((cp = getenv("MD_DEBUG")) == NULL) 177 return (0); 178 179 if (strstr(cp, "SETINFO") == NULL) 180 return (0); 181 182 (void) memset(&gsp, '\0', sizeof (md_gs_stat_parm_t)); 183 gsp.gs_setno = (*spp)->setno; 184 185 if (metaioctl(MD_GET_SETSTAT, &gsp, &gsp.gs_mde, NULL) != 0) 186 return (mdstealerror(ep, &gsp.gs_mde)); 187 188 if (fprintf(fp, "Status for set %d = ", gsp.gs_setno) == EOF) 189 goto out; 190 191 if (meta_prbits(fp, NULL, gsp.gs_status, MD_SET_STAT_BITS) == EOF) 192 goto out; 193 194 195 if (fprintf(fp, "\n") == EOF) 196 goto out; 197 198 /* success */ 199 rval = 0; 200 201 /* cleanup, return error */ 202 out: 203 if (rval != 0) 204 (void) mdsyserror(ep, errno, fname); 205 206 return (rval); 207 } 208 209 /* 210 * check_replica_state: 211 * If the replica state is stale or the set has been halted 212 * this routine returns an error. 213 */ 214 static int 215 check_replica_state(mdsetname_t *sp, md_error_t *ep) 216 { 217 mddb_config_t c; 218 219 (void) memset(&c, 0, sizeof (c)); 220 c.c_id = 0; 221 c.c_setno = sp->setno; 222 223 if (metaioctl(MD_DB_GETDEV, &c, &c.c_mde, NULL) != 0) { 224 if (mdismddberror(&c.c_mde, MDE_DB_INVALID)) 225 (void) mdstealerror(ep, &c.c_mde); 226 return (-1); 227 } 228 229 if (c.c_flags & MDDB_C_STALE) { 230 return (mdmddberror(ep, MDE_DB_STALE, NODEV32, sp->setno, 231 0, NULL)); 232 } else 233 return (0); 234 } 235 236 static void 237 print_trans_msg(mdprtopts_t options, int meta_print_trans_msg) 238 { 239 if (meta_print_trans_msg != 0) { 240 (void) fprintf(stderr, "\n\n"); 241 if (options & PRINT_SHORT) { 242 (void) fprintf(stderr, gettext(MD_SHORT_EOF_TRANS_MSG)); 243 (void) fprintf(stderr, 244 gettext(MD_SHORT_EOF_TRANS_WARNING)); 245 } else { 246 (void) fprintf(stderr, gettext(MD_EOF_TRANS_MSG)); 247 (void) 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 (void) 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 (void) 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 (void) 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 (void) metanamelist_append(&nlp, hsp->hsnamep); 747 /* print hotspare */ 748 if (hsp->state == HSS_AVAILABLE) { 749 if (hotspare_ok(bname)) 750 continue; 751 752 (void) 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 mdclrerror(&e); 760 } else { 761 deleted_hs++; 762 } 763 } 764 } 765 } 766 767 768 769 /* 770 * Generic routine to issue ioctls 771 */ 772 773 void 774 md_setprobetest(md_probedev_t *iocp) 775 { 776 (void) strcpy(iocp->test_name, MD_PROBE_OPEN_T); 777 } 778 779 int 780 md_probe_ioctl(mdsetname_t *sp, mdnamelist_t *nlp, int ndevs, char *drvname) 781 { 782 mdnamelist_t *p; 783 mdname_t *np; 784 md_probedev_t probe_ioc, *iocp; 785 int i, retval = 0; 786 /* 787 * Allocate space for all the metadevices and fill in 788 * the minor numbers. 789 */ 790 791 (void) memset(&probe_ioc, 0, sizeof (probe_ioc)); 792 iocp = &probe_ioc; 793 794 if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t))) 795 == 0) { 796 perror("md_probe_ioctl: calloc"); 797 return (-1); 798 } 799 800 MD_SETDRIVERNAME(iocp, drvname, sp->setno); 801 md_setprobetest(iocp); 802 803 iocp->nmdevs = ndevs; 804 805 for (p = nlp, i = 0; p; p = p->next, i++) { 806 np = p->namep; 807 ((minor_t *)(uintptr_t)iocp->mnum_list)[i] = 808 meta_getminor(np->dev); 809 } 810 811 812 if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0) 813 retval = -1; 814 Free((void *)(uintptr_t)iocp->mnum_list); 815 return (retval); 816 } 817 /* 818 * 819 * - remove p from nlp list 820 * - put it on the toplp list. 821 * - update the p to the next element 822 */ 823 824 void 825 add_to_list(mdnamelist_t **curpp, mdnamelist_t **prevpp, mdnamelist_t **newlpp) 826 { 827 mdnamelist_t *p, *prevp, *nlp; 828 829 p = *curpp; 830 prevp = *prevpp; 831 nlp = *newlpp; 832 833 if (prevp == p) { 834 /* if first element reset prevp */ 835 prevp = p->next; 836 p->next = nlp; 837 nlp = p; 838 p = prevp; 839 } else { 840 prevp->next = p->next; 841 p->next = nlp; 842 nlp = p; 843 p = prevp->next; 844 } 845 *curpp = p; 846 *prevpp = prevp; 847 *newlpp = nlp; 848 } 849 /* 850 * Scans the given list of metadeivces and returns a list of top level 851 * metadevices. 852 * Note: The orignal list is not valid at the end and is set to NULL. 853 */ 854 855 int 856 get_toplevel_mds(mdsetname_t *sp, mdnamelist_t **lpp, 857 mdnamelist_t **top_pp) 858 { 859 mdnamelist_t *p, *prevp, *toplp; 860 int ntopmd; 861 md_common_t *mdp; 862 md_error_t e = mdnullerror; 863 864 ntopmd = 0; 865 prevp = p = *lpp; 866 toplp = NULL; 867 868 while (p) { 869 if ((mdp = meta_get_unit(sp, p->namep, &e)) == NULL) { 870 prevp = p; 871 p = p->next; 872 continue; 873 } 874 875 if (mdp->parent == MD_NO_PARENT) { 876 /* increment the top level md count. */ 877 ntopmd++; 878 add_to_list(&p, &prevp, &toplp); 879 } else { 880 prevp = p; 881 p = p->next; 882 } 883 } 884 *lpp = NULL; 885 *top_pp = toplp; 886 887 return (ntopmd); 888 } 889 890 int 891 get_namelist(mdnamelist_t **transdevlist, mdnamelist_t **devlist, 892 char *dev_type) 893 { 894 mdnamelist_t *np, *prevp; 895 md_error_t e = mdnullerror; 896 char *type_name; 897 int i = 0; 898 899 prevp = np = *transdevlist; 900 while (np) { 901 if ((type_name = metagetmiscname(np->namep, &e)) == NULL) { 902 *devlist = NULL; 903 return (-1); 904 } 905 if (strcmp(type_name, dev_type) == 0) { 906 /* move it to the devlist */ 907 add_to_list(&np, &prevp, devlist); 908 i++; 909 } else { 910 prevp = np; 911 np = np->next; 912 } 913 } 914 return (i); 915 } 916 917 918 mdnamelist_t * 919 create_nlp(mdsetname_t *sp) 920 { 921 mdnamelist_t *np; 922 md_error_t e = mdnullerror; 923 924 if (np = (mdnamelist_t *)malloc(sizeof (mdnamelist_t))) { 925 np->next = NULL; 926 return (np); 927 } else { 928 /* error condition below */ 929 mde_perror(&e, "create_nlp: malloc failed\n"); 930 md_exit(sp, 1); 931 } 932 return (0); 933 } 934 935 /* 936 * Create a list of metadevices associated with trans. top_pp points to 937 * this list. The number of components in the list are also returned. 938 */ 939 int 940 create_trans_compslist(mdsetname_t *sp, mdnamelist_t **lpp, 941 mdnamelist_t **top_pp) 942 { 943 mdnamelist_t *p, *tailp, *toplp, *newlp; 944 int ntoptrans; 945 md_error_t e = mdnullerror; 946 md_trans_t *tp; 947 948 ntoptrans = 0; 949 p = *lpp; 950 tailp = toplp = NULL; 951 /* 952 * Scan the current list of trans devices. From that 953 * extract all the lower level metadevices and put them on 954 * toplp list. 955 */ 956 957 while (p) { 958 if (tp = meta_get_trans(sp, p->namep, &e)) { 959 /* 960 * Check the master and log devices to see if they 961 * are metadevices 962 */ 963 if (metaismeta(tp->masternamep)) { 964 /* get a mdnamelist_t. */ 965 newlp = create_nlp(sp); 966 newlp->namep = tp->masternamep; 967 if (toplp == NULL) { 968 toplp = tailp = newlp; 969 } else { 970 tailp->next = newlp; 971 tailp = newlp; 972 } 973 ntoptrans++; 974 } 975 976 if (tp->lognamep && metaismeta(tp->lognamep)) { 977 newlp = create_nlp(sp); 978 newlp->namep = tp->lognamep; 979 if (toplp == NULL) { 980 toplp = tailp = newlp; 981 } else { 982 tailp->next = newlp; 983 tailp = newlp; 984 } 985 ntoptrans++; 986 } 987 p = p->next; 988 } 989 } 990 *top_pp = toplp; 991 return (ntoptrans); 992 } 993 994 void 995 probe_mirror_devs(mdsetname_t *sp) 996 { 997 mdnamelist_t *nlp, *toplp; 998 int cnt; 999 md_error_t e = mdnullerror; 1000 1001 nlp = toplp = NULL; 1002 1003 if (meta_get_mirror_names(sp, &nlp, 0, &e) > 0) { 1004 /* 1005 * We have some mirrors to probe 1006 * get a list of top-level mirrors 1007 */ 1008 1009 cnt = get_toplevel_mds(sp, &nlp, &toplp); 1010 if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_MIRROR) < 0)) 1011 perror("MD_IOCPROBE_DEV"); 1012 } else { 1013 mdclrerror(&e); 1014 } 1015 metafreenamelist(nlp); 1016 metafreenamelist(toplp); 1017 1018 } 1019 1020 void 1021 probe_raid_devs(mdsetname_t *sp) 1022 { 1023 mdnamelist_t *nlp, *toplp; 1024 int cnt; 1025 md_error_t e = mdnullerror; 1026 1027 nlp = toplp = NULL; 1028 1029 if (meta_get_raid_names(sp, &nlp, 0, &e) > 0) { 1030 /* 1031 * We have some mirrors to probe 1032 * get a list of top-level mirrors 1033 */ 1034 1035 cnt = get_toplevel_mds(sp, &nlp, &toplp); 1036 1037 if (cnt && (md_probe_ioctl(sp, toplp, cnt, MD_RAID) < 0)) 1038 perror("MD_IOCPROBE_DEV"); 1039 } else { 1040 mdclrerror(&e); 1041 } 1042 metafreenamelist(nlp); 1043 metafreenamelist(toplp); 1044 } 1045 1046 /* 1047 * Trans probes are diffenent. -- so whats new. 1048 * we separate out the master and log device and then issue the 1049 * probe calls. 1050 * Since the underlying device could be disk, stripe, RAID or miror, 1051 * we have to sort them out and then call the ioctl for each. 1052 */ 1053 1054 void 1055 probe_trans_devs(mdsetname_t *sp) 1056 { 1057 mdnamelist_t *nlp, *toplp; 1058 mdnamelist_t *trans_raidlp, *trans_mmlp, *trans_stripelp; 1059 int cnt; 1060 md_error_t e = mdnullerror; 1061 1062 nlp = toplp = NULL; 1063 trans_raidlp = trans_mmlp = trans_stripelp = NULL; 1064 1065 if (meta_get_trans_names(sp, &nlp, 0, &e) > 0) { 1066 /* 1067 * get a list of master and log metadevices. 1068 */ 1069 1070 cnt = create_trans_compslist(sp, &nlp, &toplp); 1071 1072 /* underlying RAID-5 components */ 1073 1074 cnt = get_namelist(&toplp, &trans_raidlp, MD_RAID); 1075 if ((cnt > 0) && (md_probe_ioctl(sp, trans_raidlp, cnt, 1076 MD_RAID) < 0)) 1077 perror("MD_IOCPROBE_DEV"); 1078 1079 metafreenamelist(trans_raidlp); 1080 1081 /* underlying mirror components */ 1082 1083 cnt = get_namelist(&toplp, &trans_mmlp, MD_MIRROR); 1084 1085 if ((cnt > 0) && (md_probe_ioctl(sp, trans_mmlp, cnt, 1086 MD_MIRROR) < 0)) 1087 perror("MD_IOCPROBE_DEV"); 1088 1089 metafreenamelist(trans_mmlp); 1090 1091 /* underlying stripe components */ 1092 1093 cnt = get_namelist(&toplp, &trans_stripelp, MD_STRIPE); 1094 if ((cnt > 0) && (md_probe_ioctl(sp, trans_stripelp, cnt, 1095 MD_STRIPE) < 0)) 1096 perror("MD_IOCPROBE_DEV"); 1097 metafreenamelist(trans_stripelp); 1098 metafreenamelist(nlp); 1099 } else { 1100 mdclrerror(&e); 1101 } 1102 } 1103 1104 /* 1105 * probe hot spares. This is differs from other approaches since 1106 * there are no read/write routines through md. We check at the physical 1107 * component level and then delete it if its bad. 1108 */ 1109 1110 void 1111 probe_hotspare_devs(mdsetname_t *sp) 1112 { 1113 mdhspnamelist_t *hspnlp = NULL; 1114 mdhspnamelist_t *p; 1115 md_hsp_t *hspp; 1116 md_error_t e = mdnullerror; 1117 1118 if (meta_get_hsp_names(sp, &hspnlp, 0, &e) <= 0) { 1119 mdclrerror(&e); 1120 return; 1121 } 1122 for (p = hspnlp; (p != NULL); p = p->next) { 1123 mdhspname_t *hspnp = p->hspnamep; 1124 1125 if ((hspp = meta_get_hsp(sp, hspnp, &e)) == NULL) 1126 continue; 1127 1128 if (hspp->hotspares.hotspares_len != 0) { 1129 delete_hotspares_impl(sp, hspnp, hspp); 1130 } 1131 } 1132 metafreehspnamelist(hspnlp); 1133 mdclrerror(&e); 1134 } 1135 1136 static void 1137 probe_all_devs(mdsetname_t *sp) 1138 { 1139 probe_hotspare_devs(sp); 1140 probe_mirror_devs(sp); 1141 probe_raid_devs(sp); 1142 probe_trans_devs(sp); 1143 } 1144 1145 /* 1146 * The following functions are used to print the concise output 1147 * of the metastat coommand (-c option). 1148 * 1149 * Normally the output for metastat is performed within libmeta via 1150 * the *_report functions within each of the metadevice specific files in 1151 * libmeta. However, it is usually bad architecture for a library to 1152 * perform output since there are so many different ways that an application 1153 * can choose to do output (e.g. GUI, CLI, CIM, SNMP, etc.). So, for the 1154 * concise output option we have moved the CLI output to the metastat 1155 * code and just use libmeta as the source of data to be printed. 1156 * 1157 * This function gets all of the different top-level metadevices in the set 1158 * and prints them. It calls the print_concise_md() function to recursively 1159 * print the metadevices that underly the top-level metadevices. It does 1160 * special handling for soft partitions so that all of the SPs on the 1161 * same underlying device are grouped and then that underlying device 1162 * is only printed once. 1163 */ 1164 static void 1165 print_concise_diskset(mdsetname_t *sp) 1166 { 1167 md_error_t error = mdnullerror; 1168 mdnamelist_t *nl = NULL; 1169 mdhspnamelist_t *hsp_list = NULL; 1170 1171 /* 1172 * We do extra handling for soft parts since we want to find 1173 * all of the SPs on the same underlying device, group them and 1174 * print them together before printing the underlying device just 1175 * once. This logic doesn't apply to any other metadevice type. 1176 */ 1177 if (meta_get_sp_names(sp, &nl, 0, &error) >= 0) { 1178 mdnamelist_t *nlp; 1179 /* keep track of the softparts on the same underlying device */ 1180 struct sp_base_list *base_list = NULL; 1181 1182 for (nlp = nl; nlp != NULL; nlp = nlp->next) { 1183 mdname_t *mdn; 1184 md_sp_t *soft_part; 1185 mdnamelist_t *tnlp; 1186 1187 mdn = metaname(&sp, nlp->namep->cname, 1188 META_DEVICE, &error); 1189 mdclrerror(&error); 1190 if (mdn == NULL) { 1191 print_concise_entry(0, nlp->namep->cname, 1192 0, 'p'); 1193 (void) printf("\n"); 1194 continue; 1195 } 1196 1197 soft_part = meta_get_sp_common(sp, mdn, 1, &error); 1198 mdclrerror(&error); 1199 1200 if (soft_part == NULL || 1201 MD_HAS_PARENT(soft_part->common.parent) || 1202 sp_done(soft_part, base_list)) 1203 continue; 1204 1205 /* print this soft part */ 1206 print_concise_entry(0, soft_part->common.namep->cname, 1207 soft_part->common.size, 'p'); 1208 (void) printf(" %s\n", soft_part->compnamep->cname); 1209 1210 /* 1211 * keep track of the underlying device of 1212 * this soft part 1213 */ 1214 base_list = sp_add_done(soft_part, base_list); 1215 1216 /* 1217 * now print all of the other soft parts on the same 1218 * underlying device 1219 */ 1220 for (tnlp = nlp->next; tnlp != NULL; tnlp = 1221 tnlp->next) { 1222 md_sp_t *part; 1223 1224 mdn = metaname(&sp, tnlp->namep->cname, 1225 META_DEVICE, &error); 1226 1227 mdclrerror(&error); 1228 if (mdn == NULL) 1229 continue; 1230 1231 part = meta_get_sp_common(sp, mdn, 1, &error); 1232 mdclrerror(&error); 1233 1234 if (part == NULL || MD_HAS_PARENT( 1235 part->common.parent) || 1236 ! sp_match(part, base_list)) 1237 continue; 1238 1239 /* on the same base so print this soft part */ 1240 print_concise_entry(0, 1241 part->common.namep->cname, 1242 part->common.size, 'p'); 1243 (void) printf(" %s\n", part->compnamep->cname); 1244 } 1245 1246 /* 1247 * print the common metadevice hierarchy 1248 * under these soft parts 1249 */ 1250 print_concise_md(META_INDENT, sp, soft_part->compnamep); 1251 } 1252 1253 free_names(&nl); 1254 sp_free_list(base_list); 1255 } 1256 mdclrerror(&error); 1257 1258 if (meta_get_trans_names(sp, &nl, 0, &error) >= 0) 1259 print_concise_namelist(sp, &nl, 't'); 1260 mdclrerror(&error); 1261 1262 if (meta_get_mirror_names(sp, &nl, 0, &error) >= 0) 1263 print_concise_namelist(sp, &nl, 'm'); 1264 mdclrerror(&error); 1265 1266 if (meta_get_raid_names(sp, &nl, 0, &error) >= 0) 1267 print_concise_namelist(sp, &nl, 'r'); 1268 mdclrerror(&error); 1269 1270 if (meta_get_stripe_names(sp, &nl, 0, &error) >= 0) 1271 print_concise_namelist(sp, &nl, 's'); 1272 mdclrerror(&error); 1273 1274 if (meta_get_hsp_names(sp, &hsp_list, 0, &error) >= 0) { 1275 mdhspnamelist_t *nlp; 1276 1277 for (nlp = hsp_list; nlp != NULL; nlp = nlp->next) { 1278 md_hsp_t *hsp; 1279 1280 print_concise_entry(0, nlp->hspnamep->hspname, 0, 'h'); 1281 1282 hsp = meta_get_hsp_common(sp, nlp->hspnamep, 1, &error); 1283 mdclrerror(&error); 1284 if (hsp != NULL) { 1285 int i; 1286 1287 for (i = 0; i < hsp->hotspares.hotspares_len; i++) { 1288 md_hs_t *hs; 1289 char *state; 1290 1291 hs = &hsp->hotspares.hotspares_val[i]; 1292 1293 (void) printf(" %s", hs->hsnamep->cname); 1294 1295 state = get_hs_state(hs); 1296 if (state != NULL) 1297 (void) printf(" (%s)", state); 1298 } 1299 } 1300 1301 (void) printf("\n"); 1302 } 1303 1304 mdclrerror(&error); 1305 metafreehspnamelist(hsp_list); 1306 } 1307 } 1308 1309 /* 1310 * Print the top-level metadevices in the name list for concise output. 1311 */ 1312 static void 1313 print_concise_namelist(mdsetname_t *sp, mdnamelist_t **nl, char mtype) 1314 { 1315 mdnamelist_t *nlp; 1316 md_error_t error = mdnullerror; 1317 1318 for (nlp = *nl; nlp != NULL; nlp = nlp->next) { 1319 mdname_t *mdn; 1320 md_common_t *u; 1321 1322 mdn = metaname(&sp, nlp->namep->cname, META_DEVICE, &error); 1323 mdclrerror(&error); 1324 if (mdn == NULL) { 1325 print_concise_entry(0, nlp->namep->cname, 0, mtype); 1326 (void) printf("\n"); 1327 continue; 1328 } 1329 1330 u = get_concise_unit(sp, mdn, &error); 1331 mdclrerror(&error); 1332 1333 if (u != NULL && !MD_HAS_PARENT(u->parent)) 1334 print_concise_md(0, sp, mdn); 1335 } 1336 1337 free_names(nl); 1338 } 1339 1340 /* 1341 * Concise mirror output. 1342 */ 1343 static void 1344 print_concise_mirror(int indent, mdsetname_t *sp, md_mirror_t *mirror) 1345 { 1346 md_error_t error = mdnullerror; 1347 int i; 1348 md_status_t status = mirror->common.state; 1349 1350 if (mirror == NULL) 1351 return; 1352 1353 print_concise_entry(indent, mirror->common.namep->cname, 1354 mirror->common.size, 'm'); 1355 1356 for (i = 0; i < NMIRROR; i++) { 1357 uint_t tstate = 0; 1358 char *state; 1359 1360 if (mirror->submirrors[i].submirnamep == NULL) 1361 continue; 1362 (void) printf(" %s", mirror->submirrors[i].submirnamep->cname); 1363 1364 if (mirror->submirrors[i].state & SMS_OFFLINE) { 1365 (void) printf(gettext(" (offline)")); 1366 continue; 1367 } 1368 1369 if (metaismeta(mirror->submirrors[i].submirnamep)) 1370 (void) meta_get_tstate( 1371 mirror->submirrors[i].submirnamep->dev, 1372 &tstate, &error); 1373 1374 mdclrerror(&error); 1375 state = get_sm_state(mirror, i, status, tstate); 1376 if (state != NULL) 1377 (void) printf(" (%s)", state); 1378 } 1379 1380 (void) printf("\n"); 1381 1382 indent += META_INDENT; 1383 for (i = 0; i < NMIRROR; i++) { 1384 if (mirror->submirrors[i].submirnamep == NULL) 1385 continue; 1386 1387 print_concise_md(indent, sp, mirror->submirrors[i].submirnamep); 1388 } 1389 } 1390 1391 /* 1392 * Concise raid output. 1393 */ 1394 static void 1395 print_concise_raid(int indent, mdsetname_t *sp, md_raid_t *raid) 1396 { 1397 md_error_t error = mdnullerror; 1398 int i; 1399 uint_t tstate = 0; 1400 1401 if (raid == NULL) 1402 return; 1403 1404 print_concise_entry(indent, raid->common.namep->cname, 1405 raid->common.size, 'r'); 1406 1407 if (metaismeta(raid->common.namep)) 1408 (void) meta_get_tstate(raid->common.namep->dev, 1409 &tstate, &error); 1410 1411 for (i = 0; i < raid->cols.cols_len; i++) { 1412 md_raidcol_t *colp = &raid->cols.cols_val[i]; 1413 mdname_t *namep = ((colp->hsnamep != NULL) ? 1414 colp->hsnamep : colp->colnamep); 1415 char *hsname = ((colp->hsnamep != NULL) ? 1416 colp->hsnamep->cname : NULL); 1417 char *col_state = NULL; 1418 1419 (void) printf(" %s", colp->colnamep->cname); 1420 1421 if (metaismeta(namep)) { 1422 uint_t tstate = 0; 1423 1424 (void) meta_get_tstate(namep->dev, &tstate, &error); 1425 mdclrerror(&error); 1426 col_state = get_raid_col_state(colp, tstate); 1427 1428 } else { 1429 if (tstate != 0) 1430 col_state = "-"; 1431 else 1432 col_state = get_raid_col_state(colp, tstate); 1433 } 1434 1435 if (col_state != NULL) { 1436 if (hsname != NULL) 1437 (void) printf(" (%s-%s)", col_state, hsname); 1438 else 1439 (void) printf(" (%s)", col_state); 1440 1441 } else if (hsname != NULL) { 1442 (void) printf(gettext(" (spared-%s)"), hsname); 1443 } 1444 } 1445 1446 (void) printf("\n"); 1447 1448 indent += META_INDENT; 1449 for (i = 0; i < raid->cols.cols_len; i++) { 1450 print_concise_md(indent, sp, raid->cols.cols_val[i].colnamep); 1451 } 1452 } 1453 1454 /* 1455 * Concise stripe output. 1456 */ 1457 static void 1458 print_concise_stripe(int indent, mdsetname_t *sp, md_stripe_t *stripe) 1459 { 1460 md_error_t error = mdnullerror; 1461 int i; 1462 uint_t top_tstate = 0; 1463 1464 if (stripe == NULL) 1465 return; 1466 1467 print_concise_entry(indent, stripe->common.namep->cname, 1468 stripe->common.size, 's'); 1469 1470 if (metaismeta(stripe->common.namep)) 1471 (void) meta_get_tstate(stripe->common.namep->dev, &top_tstate, 1472 &error); 1473 mdclrerror(&error); 1474 1475 for (i = 0; i < stripe->rows.rows_len; i++) { 1476 md_row_t *rowp; 1477 int j; 1478 1479 rowp = &stripe->rows.rows_val[i]; 1480 1481 for (j = 0; j < rowp->comps.comps_len; j++) { 1482 md_comp_t *comp; 1483 uint_t tstate = 0; 1484 char *comp_state = NULL; 1485 char *hsname; 1486 1487 comp = &rowp->comps.comps_val[j]; 1488 (void) printf(" %s", comp->compnamep->cname); 1489 1490 if (metaismeta(comp->compnamep)) { 1491 uint_t tstate = 0; 1492 (void) meta_get_tstate(comp->compnamep->dev, 1493 &tstate, &error); 1494 mdclrerror(&error); 1495 comp_state = get_stripe_state(comp, tstate); 1496 } else { 1497 if (top_tstate != 0) 1498 comp_state = "-"; 1499 else 1500 comp_state = get_stripe_state(comp, tstate); 1501 } 1502 1503 hsname = ((comp->hsnamep != NULL) ? 1504 comp->hsnamep->cname : NULL); 1505 1506 if (comp_state != NULL) { 1507 if (hsname != NULL) 1508 (void) printf(" (%s-%s)", 1509 comp_state, hsname); 1510 else 1511 (void) printf(" (%s)", comp_state); 1512 1513 } else if (hsname != NULL) { 1514 (void) printf(gettext(" (spared-%s)"), hsname); 1515 } 1516 } 1517 } 1518 1519 (void) printf("\n"); 1520 1521 indent += META_INDENT; 1522 for (i = 0; i < stripe->rows.rows_len; i++) { 1523 md_row_t *rowp; 1524 int j; 1525 1526 rowp = &stripe->rows.rows_val[i]; 1527 1528 for (j = 0; j < rowp->comps.comps_len; j++) { 1529 print_concise_md(indent, sp, 1530 rowp->comps.comps_val[j].compnamep); 1531 } 1532 } 1533 } 1534 1535 /* 1536 * Concise soft partition output. 1537 */ 1538 static void 1539 print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part) 1540 { 1541 if (part == NULL) 1542 return; 1543 1544 print_concise_entry(indent, part->common.namep->cname, 1545 part->common.size, 'p'); 1546 1547 (void) printf(" %s\n", part->compnamep->cname); 1548 1549 print_concise_md(indent + META_INDENT, sp, part->compnamep); 1550 } 1551 1552 /* 1553 * Concise trans output. 1554 */ 1555 static void 1556 print_concise_trans(int indent, mdsetname_t *sp, md_trans_t *trans) 1557 { 1558 if (trans == NULL) 1559 return; 1560 1561 print_concise_entry(indent, trans->common.namep->cname, 1562 trans->common.size, 't'); 1563 1564 if (trans->masternamep != NULL) 1565 (void) printf(" %s", trans->masternamep->cname); 1566 1567 if (trans->lognamep != NULL) 1568 (void) printf(" %s", trans->lognamep->cname); 1569 1570 (void) printf("\n"); 1571 1572 indent += META_INDENT; 1573 1574 print_concise_md(indent, sp, trans->masternamep); 1575 1576 print_concise_md(indent, sp, trans->lognamep); 1577 } 1578 1579 /* 1580 * Recursive function for concise metadevice nested output. 1581 */ 1582 static void 1583 print_concise_md(int indent, mdsetname_t *sp, mdname_t *np) 1584 { 1585 md_error_t error = mdnullerror; 1586 md_unit_t *u; 1587 md_mirror_t *mirror; 1588 md_raid_t *raid; 1589 md_sp_t *soft_part; 1590 md_stripe_t *stripe; 1591 md_trans_t *trans; 1592 1593 if (np == NULL || !metaismeta(np)) 1594 return; 1595 1596 if ((u = meta_get_mdunit(sp, np, &error)) == NULL) { 1597 mdclrerror(&error); 1598 return; 1599 } 1600 1601 switch (u->c.un_type) { 1602 case MD_DEVICE: 1603 stripe = meta_get_stripe_common(sp, np, 1, &error); 1604 print_concise_stripe(indent, sp, stripe); 1605 break; 1606 1607 case MD_METAMIRROR: 1608 mirror = meta_get_mirror(sp, np, &error); 1609 print_concise_mirror(indent, sp, mirror); 1610 break; 1611 1612 case MD_METATRANS: 1613 trans = meta_get_trans_common(sp, np, 1, &error); 1614 print_concise_trans(indent, sp, trans); 1615 break; 1616 1617 case MD_METARAID: 1618 raid = meta_get_raid_common(sp, np, 1, &error); 1619 print_concise_raid(indent, sp, raid); 1620 break; 1621 1622 case MD_METASP: 1623 soft_part = meta_get_sp_common(sp, np, 1, &error); 1624 print_concise_sp(indent, sp, soft_part); 1625 break; 1626 1627 default: 1628 return; 1629 } 1630 mdclrerror(&error); 1631 } 1632 1633 /* 1634 * Given a name get the unit for use in concise output. We use the *_common 1635 * routines in libmeta which allow us to specify the "fast" flag, thereby 1636 * avoiding the DKIOCGGEOM ioctl that normally happens. 1637 */ 1638 static md_common_t * 1639 get_concise_unit(mdsetname_t *sp, mdname_t *np, md_error_t *ep) 1640 { 1641 char *miscname; 1642 1643 /* short circuit */ 1644 if (np->drivenamep->unitp != NULL) 1645 return (np->drivenamep->unitp); 1646 if (metachkmeta(np, ep) != 0) 1647 return (NULL); 1648 1649 /* dispatch */ 1650 if ((miscname = metagetmiscname(np, ep)) == NULL) 1651 return (NULL); 1652 else if (strcmp(miscname, MD_STRIPE) == 0) 1653 return ((md_common_t *)meta_get_stripe_common(sp, np, 1, ep)); 1654 else if (strcmp(miscname, MD_MIRROR) == 0) 1655 return ((md_common_t *)meta_get_mirror(sp, np, ep)); 1656 else if (strcmp(miscname, MD_TRANS) == 0) 1657 return ((md_common_t *)meta_get_trans_common(sp, np, 1, ep)); 1658 else if (strcmp(miscname, MD_RAID) == 0) 1659 return ((md_common_t *)meta_get_raid_common(sp, np, 1, ep)); 1660 else if (strcmp(miscname, MD_SP) == 0) 1661 return ((md_common_t *)meta_get_sp_common(sp, np, 1, ep)); 1662 else { 1663 (void) mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(np->dev), 1664 np->cname); 1665 return (NULL); 1666 } 1667 } 1668 1669 static void 1670 free_names(mdnamelist_t **nlp) 1671 { 1672 mdnamelist_t *p; 1673 1674 for (p = *nlp; p != NULL; p = p->next) { 1675 meta_invalidate_name(p->namep); 1676 p->namep = NULL; 1677 } 1678 metafreenamelist(*nlp); 1679 *nlp = NULL; 1680 } 1681 1682 /* 1683 * Submirror state for concise output. 1684 */ 1685 static char * 1686 get_sm_state(md_mirror_t *mirror, int i, md_status_t mirror_status, 1687 uint_t tstate) 1688 { 1689 sm_state_t state = mirror->submirrors[i].state; 1690 uint_t is_target = 1691 mirror->submirrors[i].flags & MD_SM_RESYNC_TARGET; 1692 1693 /* 1694 * Only return Unavailable if there is no flagged error on the 1695 * submirror. If the mirror has received any writes since the submirror 1696 * went into Unavailable state a resync is required. To alert the 1697 * administrator to this we return a 'Needs maintenance' message. 1698 */ 1699 if ((tstate != 0) && (state & SMS_RUNNING)) 1700 return (gettext("unavail")); 1701 1702 /* all is well */ 1703 if (state & SMS_RUNNING) { 1704 if (!(mirror_status & MD_UN_OPT_NOT_DONE) || 1705 ((mirror_status & MD_UN_OPT_NOT_DONE) && !is_target)) 1706 return (NULL); 1707 } 1708 1709 /* resyncing, needs repair */ 1710 if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC | 1711 SMS_OFFLINE_RESYNC)) || (mirror_status & MD_UN_OPT_NOT_DONE)) { 1712 static char buf[MAXPATHLEN]; 1713 1714 if (mirror_status & MD_UN_RESYNC_ACTIVE) { 1715 1716 if (mirror->common.revision & MD_64BIT_META_DEV) { 1717 (void) snprintf(buf, sizeof (buf), 1718 gettext("resync-%2d.%1d%%"), 1719 mirror->percent_done / 10, 1720 mirror->percent_done % 10); 1721 } else { 1722 (void) snprintf(buf, sizeof (buf), 1723 gettext("resync-%d%%"), mirror->percent_done); 1724 } 1725 return (buf); 1726 } 1727 return (gettext("maint")); 1728 } 1729 1730 /* needs repair */ 1731 if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE)) 1732 return (gettext("maint")); 1733 1734 /* unknown */ 1735 return (gettext("unknown")); 1736 } 1737 1738 /* 1739 * Raid component state for concise output. 1740 */ 1741 static char * 1742 get_raid_col_state(md_raidcol_t *colp, uint_t tstate) 1743 { 1744 if (tstate != 0) 1745 return (gettext("unavail")); 1746 1747 return (meta_get_raid_col_state(colp->state)); 1748 } 1749 1750 /* 1751 * Stripe state for concise output. 1752 */ 1753 static char * 1754 get_stripe_state(md_comp_t *mdcp, uint_t tstate) 1755 { 1756 comp_state_t state = mdcp->state; 1757 1758 if (tstate != 0) 1759 return ("unavail"); 1760 1761 return (meta_get_stripe_state(state)); 1762 } 1763 1764 /* 1765 * Hostspare state for concise output. 1766 */ 1767 static char * 1768 get_hs_state(md_hs_t *hsp) 1769 { 1770 hotspare_states_t state = hsp->state; 1771 1772 return (meta_get_hs_state(state)); 1773 } 1774 1775 1776 /* 1777 * Keep track of printed soft partitions for concise output. 1778 */ 1779 static struct sp_base_list * 1780 sp_add_done(md_sp_t *part, struct sp_base_list *lp) 1781 { 1782 struct sp_base_list *n; 1783 1784 n = (struct sp_base_list *)malloc(sizeof (struct sp_base_list)); 1785 if (n == NULL) 1786 return (lp); 1787 1788 if ((n->base = strdup(part->compnamep->cname)) == NULL) { 1789 free(n); 1790 return (lp); 1791 } 1792 1793 n->next = lp; 1794 1795 return (n); 1796 } 1797 1798 /* 1799 * Keep track of printed soft partitions for concise output. 1800 */ 1801 static int 1802 sp_done(md_sp_t *part, struct sp_base_list *lp) 1803 { 1804 for (; lp != NULL; lp = lp->next) { 1805 if (strcmp(lp->base, part->compnamep->cname) == 0) 1806 return (1); 1807 } 1808 1809 return (0); 1810 } 1811 1812 /* 1813 * Check the first element for a match. 1814 */ 1815 static int 1816 sp_match(md_sp_t *part, struct sp_base_list *lp) 1817 { 1818 if (lp != NULL && strcmp(lp->base, part->compnamep->cname) == 0) 1819 return (1); 1820 1821 return (0); 1822 } 1823 1824 /* 1825 * Free memory used for soft partition printed status in concise output. 1826 */ 1827 static void 1828 sp_free_list(struct sp_base_list *lp) 1829 { 1830 struct sp_base_list *n; 1831 1832 for (; lp != NULL; lp = n) { 1833 n = lp->next; 1834 free(lp->base); 1835 free(lp); 1836 } 1837 } 1838