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
print_name(mdsetname_t ** spp,char * uname,mdnamelist_t ** nlistpp,char * fname,FILE * fp,mdprtopts_t options,int * meta_print_trans_msgp,mdnamelist_t ** lognlpp,md_error_t * ep)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
print_setstat(mdsetname_t ** spp,char * fname,FILE * fp,mdprtopts_t options,md_error_t * ep)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
check_replica_state(mdsetname_t * sp,md_error_t * ep)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
print_trans_msg(mdprtopts_t options,int meta_print_trans_msg)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
usage(mdsetname_t * sp,int eval)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
main(int argc,char * argv[])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
print_all_sets(mdprtopts_t options,int concise_flag,int quiet_flg)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
print_specific_set(mdsetname_t * sp,mdprtopts_t options,int concise_flag,int quiet_flg)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
print_devid(mdsetname_t * sp,mdnamelist_t * nlp,FILE * fp,md_error_t * ep)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
hotspare_ok(char * bname)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
delete_hotspares_impl(mdsetname_t * sp,mdhspname_t * hspnp,md_hsp_t * hspp)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
md_setprobetest(md_probedev_t * iocp)774 md_setprobetest(md_probedev_t *iocp)
775 {
776 (void) strcpy(iocp->test_name, MD_PROBE_OPEN_T);
777 }
778
779 int
md_probe_ioctl(mdsetname_t * sp,mdnamelist_t * nlp,int ndevs,char * drvname)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
add_to_list(mdnamelist_t ** curpp,mdnamelist_t ** prevpp,mdnamelist_t ** newlpp)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
get_toplevel_mds(mdsetname_t * sp,mdnamelist_t ** lpp,mdnamelist_t ** top_pp)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
get_namelist(mdnamelist_t ** transdevlist,mdnamelist_t ** devlist,char * dev_type)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 *
create_nlp(mdsetname_t * sp)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
create_trans_compslist(mdsetname_t * sp,mdnamelist_t ** lpp,mdnamelist_t ** top_pp)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
probe_mirror_devs(mdsetname_t * sp)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
probe_raid_devs(mdsetname_t * sp)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
probe_trans_devs(mdsetname_t * sp)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
probe_hotspare_devs(mdsetname_t * sp)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
probe_all_devs(mdsetname_t * sp)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
print_concise_diskset(mdsetname_t * sp)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
print_concise_namelist(mdsetname_t * sp,mdnamelist_t ** nl,char mtype)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
print_concise_mirror(int indent,mdsetname_t * sp,md_mirror_t * mirror)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
print_concise_raid(int indent,mdsetname_t * sp,md_raid_t * raid)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
print_concise_stripe(int indent,mdsetname_t * sp,md_stripe_t * stripe)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
print_concise_sp(int indent,mdsetname_t * sp,md_sp_t * part)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
print_concise_trans(int indent,mdsetname_t * sp,md_trans_t * trans)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
print_concise_md(int indent,mdsetname_t * sp,mdname_t * np)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 *
get_concise_unit(mdsetname_t * sp,mdname_t * np,md_error_t * ep)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
free_names(mdnamelist_t ** nlp)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 *
get_sm_state(md_mirror_t * mirror,int i,md_status_t mirror_status,uint_t tstate)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 *
get_raid_col_state(md_raidcol_t * colp,uint_t tstate)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 *
get_stripe_state(md_comp_t * mdcp,uint_t tstate)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 *
get_hs_state(md_hs_t * hsp)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 *
sp_add_done(md_sp_t * part,struct sp_base_list * lp)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
sp_done(md_sp_t * part,struct sp_base_list * lp)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
sp_match(md_sp_t * part,struct sp_base_list * lp)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
sp_free_list(struct sp_base_list * lp)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