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