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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #include <meta.h>
27 #include <assert.h>
28 #include <ctype.h>
29 #include <mdiox.h>
30 #include <meta.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <strings.h>
35 #include <sys/lvm/md_mddb.h>
36 #include <sys/lvm/md_names.h>
37 #include <sys/lvm/md_crc.h>
38 #include <sys/lvm/md_convert.h>
39
40
41 /*
42 * Design Notes:
43 *
44 * All of the code in this file supports the addition of metastat -c output
45 * for the verbose option of metaimport. Some of this code is also used by
46 * the command metastat for concise output(cmd/lvm/util/metastat.c).
47 * The code is designed to produce the same output as metastat -c does for a
48 * given diskset--with a couple exceptions.
49 * The primary differences between the output for the metastat -c command and
50 * metastat output for metaimport -v are:
51 * - the set name is not printed next to each metadevice
52 * - top-level state information is not printed for some metadevices
53 * - the percent that a disk has completed resyncing is not listed
54 * in metaimport -v.
55 *
56 *
57 * The general layout of this file is as follows:
58 *
59 * - report_metastat_info()
60 * This is the primary entry point for the functions in this file, with
61 * the exception of several functions that are also called from
62 * cmd/io/lvm/util/metastat.c
63 * report_metastat_info() calls functions to read in all the the
64 * Directory blocks and Record blocks and then process the information
65 * needed to print out the metadevice records in the same format as
66 * metastat -c.
67 *
68 * - read_all_mdrecords()
69 * Reads in all the Directory blocks in the diskset and verifies their
70 * validity. For each Directly block, it loops through all Directory
71 * Entries and for each one that contains a metadevice record calls
72 * read_md_record(). Because the output is designed to imitate the
73 * output of metastat -c, we ignore metadevice records for
74 * optimized resync, changelog, and translog.
75 *
76 * - read_md_record()
77 * Reads in a Directory Entry and its associated Record block. The
78 * revision information for the Record block is checked and it is
79 * determined whether or not it is a 64bit Record block or a 32bit record
80 * block. For each valid Record block, it allocates an md_im_rec_t
81 * structure and calls extract_mduser_data().
82 *
83 * - extract_mduser_data()
84 * Populates the md_im_rec_t data structure with information about the
85 * record's associated metadevice. Also, the name of the metadevice is
86 * either copied from the NM namespace(if it exists there) or is generated
87 * from the record's un_self_id.
88 *
89 * - process_toplevel_devices()
90 * For a given metadevice type, searchs through the md_im_rec_t **mdimpp,
91 * list of all metadevices in the set, to find all records of the
92 * specified type that do not have a parent and puts them on a temp list.
93 * The temp list is then iterated through and the associated processing
94 * function is called.
95 *
96 * - process_(trans, hotspare, hotspare_pool, soft_part, mirror, stripe, raid)
97 * These functions are called by using the dfunc field in the mdimpp list.
98 * Each process function only understands its own type of metadevice. Once
99 * it processes the metadevice it was called for, it then loops through
100 * all of the underlying metadevices. After printing the name of the
101 * underlying metadevice, it puts in on a list to be processed. If the
102 * underlying device is a physical device, then print_physical_device is
103 * called.
104 * Once all information about the original metadevice is processed, it
105 * loops through the list of underlying metadevices and calls the
106 * appropriate function to process them.
107 *
108 * - process_toplevel_softparts()
109 * To match the output for metastat -c, all top-level softpartions
110 * are printed out in groups based on their underlying metadevice--so that
111 * the underlying metadevice only needs to be processed once.
112 *
113 * - meta_get_(sm_state, raid_col_state, stripe_state, hs_state)
114 * These functions are used to retrieve the metadevice state information.
115 * They are also used by the metastat concise routines in
116 * cmd/lvm/util/metastat.c.
117 *
118 */
119
120
121 /*
122 * md_im_rec is a doubly linked list used to store the rb_data for each
123 * directory entry that corresponds to a metadevice.
124 * n_key: is set, if there is an associated entry in the NM namespace.
125 * dfunc: is set to point to the function that processes the particular
126 * metadevice associated with the record.
127 * hs_record_id: is only set, if the metadevice is a hotspare.
128 * un_self_id: is set for all other records. This is also used to generate
129 * the name of the metadevice if there is no entry for the metadevice in
130 * the NM namespace--n_key is not set.
131 */
132 typedef struct md_im_rec {
133 mdkey_t n_key; /* NM namespace key */
134 struct md_im_rec *next;
135 struct md_im_rec *prev;
136 uint_t md_type;
137 uint_t has_parent; /* either 0(no parent) or 1 */
138 minor_t un_self_id;
139 mddb_recid_t hs_record_id; /* hotspare recid */
140 char *n_name; /* name of metadevice */
141 void (*dfunc) ();
142 ushort_t record_len;
143 /* pointer to the unit structure for the metadevice, e.g. rb_data[0] */
144 void *record;
145 } md_im_rec_t;
146
147 /*
148 * md_im_list is used to group toplevel metadevices by type and to group
149 * the underlying devices for a particular metadevice.
150 */
151 typedef struct md_im_list {
152 struct md_im_list *next;
153 struct md_im_rec *mdrec;
154 } md_im_list_t;
155
156
157 /*
158 * MAXSIZEMDRECNAME is the value that has historically been used to allocate
159 * space for the metadevice name
160 */
161 #define MAXSIZEMDRECNAME 20
162 #define NAMEWIDTH 16
163 #define NOT_PHYSICAL_DEV 0
164 #define PHYSICAL_DEV 1
165
166
167 /*
168 * strip_blacks()
169 *
170 * Strip blanks from string. Used for size field in concise output.
171 */
172 static char *
173 strip_blanks(char *s)
174 {
175 char *p;
176
177 for (p = s; *p; ) {
178 if (*p == ' ') {
179 char *t;
180 for (t = p; *t; t++) {
181 *t = *(t + 1);
182 }
183 } else {
184 p++;
185 }
186 }
187
188 return (s);
189 }
190
191
192 /*
193 * print_concise_entry()
194 *
195 * Print properly indented metadevice name, type and size for concise output.
196 * This function is also called from: cmd/lvm/util/metastat.c.
197 */
198 void
199 print_concise_entry(int indent, char *name, diskaddr_t size, char mtype)
200 {
201 int i;
202 int width = NAMEWIDTH; /* minumum field width for name */
203 char in[MAXPATHLEN];
204 char *sz;
205
206 in[0] = 0;
207 for (i = 0; i < indent; i++)
208 (void) strlcat(in, " ", sizeof (in));
209
210 /* set up minimum field width. negative for left justified */
211 width -= indent;
212 if (width < 0)
213 width = 0; /* overflowed; no minimum field needed */
214 else
215 width = 0 - width; /* negative for left justification */
216
217 if (size == 0) {
218 sz = "-";
219 } else {
220 sz = strip_blanks(meta_number_to_string(size, DEV_BSIZE));
221 }
222
223 (void) printf("%s%*s %c %6s", in, width, name, mtype, sz);
224 }
225
226
227 /*
228 * free_mdrec_list_entry()
229 *
230 * Removing entry from the list of metadevices in the diskset(mdimpp).
231 * This function will not remove the dummy entry at the head of the
232 * list, so we don't have to set mdrec equal to NULL.
233 */
234 static void
235 free_mdrec_list_entry(md_im_rec_t **mdrec)
236 {
237 (*mdrec)->prev->next = (*mdrec)->next;
238 if ((*mdrec)->next != NULL) {
239 (*mdrec)->next->prev = (*mdrec)->prev;
240 }
241 Free((*mdrec)->record);
242 Free((*mdrec)->n_name);
243 Free(*mdrec);
244 }
245
246
247 /*
248 * ucomponent_append()
249 *
250 * Appending entry to the underlying component list. The list
251 * is used to group all of the underlying devices before
252 * processing them.
253 */
254 static void
255 ucomponent_append(
256 md_im_list_t **ucomp_head,
257 md_im_list_t **ucomp_tail,
258 md_im_list_t *ucomp
259 )
260 {
261 ucomp->next = NULL;
262 if (*ucomp_head == NULL) {
263 *ucomp_head = ucomp;
264 *ucomp_tail = ucomp;
265 } else {
266 (*ucomp_tail)->next = ucomp;
267 *ucomp_tail = (*ucomp_tail)->next;
268 }
269 }
270
271
272 /*
273 * free_md_im_list_entries()
274 *
275 * Freeing entries on an md_im_list_t. This list is used to group
276 * underlying components for processing and to group top-level metadevices
277 * by type.
278 */
279 static void
280 free_md_im_list_entries(md_im_list_t **list_head)
281 {
282 md_im_list_t *tmp_list_entry = *list_head;
283 md_im_list_t *rm_list_entry;
284
285 while (tmp_list_entry != NULL) {
286 rm_list_entry = tmp_list_entry;
287 tmp_list_entry = tmp_list_entry->next;
288 Free(rm_list_entry);
289 }
290 }
291
292
293 /*
294 * print_physical_device()
295 *
296 * If a metadevice has an underlying component that is a physical
297 * device, then this searches the pnm_rec_t list to match an entry's
298 * n_key to the key for the underlying component. The ctd name of the
299 * physical device is printed on the same line as the metadevice.
300 */
301 static void
302 print_physical_device(
303 pnm_rec_t *phys_nm,
304 mdkey_t key
305 )
306 {
307 pnm_rec_t *tmpphys_nm;
308
309 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
310 tmpphys_nm = tmpphys_nm->next) {
311 if (tmpphys_nm->n_key == key) {
312 (void) printf(" %s", tmpphys_nm->n_name);
313 break;
314 }
315 }
316 }
317
318
319 /*
320 * get_stripe_req_size()
321 *
322 * Given a 64bit stripe unit, compute the size of the stripe unit.
323 * This function is a derivation of:
324 * common/lvm/md_convert.c:get_big_stripe_req_size()
325 * and any changes made to either this function or get_big_stripe_req_size()
326 * should be reviewed to make sure the functionality in both places is correct.
327 *
328 * Returns:
329 * total size of the 64bit stripe
330 */
331 size_t
332 get_stripe_req_size(ms_unit_t *un)
333 {
334 struct ms_row *mdr;
335 uint_t row;
336 uint_t ncomps = 0;
337 size_t mdsize = 0;
338 size_t first_comp = 0;
339
340
341 /* Compute the offset of the first component */
342 first_comp = sizeof (ms_unit_t) +
343 sizeof (struct ms_row) * (un->un_nrows - 1);
344 first_comp = roundup(first_comp, sizeof (long long));
345
346 /*
347 * Requestor wants to have the total size, add the sizes of
348 * all components
349 */
350 mdr = &un->un_row[0];
351 for (row = 0; (row < un->un_nrows); row++)
352 ncomps += mdr[row].un_ncomp;
353 mdsize = first_comp + sizeof (ms_comp_t) * ncomps;
354 return (mdsize);
355 }
356
357
358 /*
359 * meta_get_sm_state()
360 *
361 * Gets the state for the underlying components(submirrors) of a mirror.
362 * This function is also called from: cmd/lvm/util/metastat.c.
363 *
364 * Returns:
365 * string for state of the sub-mirror
366 */
367 static char *
368 meta_get_sm_state(
369 sm_state_t state
370 )
371 {
372 /* all is well */
373 if (state & SMS_RUNNING) {
374 return (NULL);
375 }
376
377 /* resyncing, needs repair */
378 if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC |
379 SMS_OFFLINE_RESYNC))) {
380 return (gettext("resyncing"));
381 }
382
383 /* needs repair */
384 if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE))
385 return (gettext("maint"));
386
387 /* unknown */
388 return (gettext("unknown"));
389 }
390
391
392 /*
393 * meta_get_raid_col_state()
394 *
395 * Gets the state for the underlying components(columns) of a raid.
396 * This function is also called from: cmd/lvm/util/metastat.c.
397 *
398 * Returns:
399 * string for state of the raid column
400 *
401 */
402 char *
403 meta_get_raid_col_state(
404 rcs_state_t state
405 )
406 {
407 switch (state) {
408 case RCS_INIT:
409 return (gettext("initializing"));
410 case RCS_OKAY:
411 return (NULL);
412 case RCS_INIT_ERRED:
413 /*FALLTHROUGH*/
414 case RCS_ERRED:
415 return (gettext("maint"));
416 case RCS_LAST_ERRED:
417 return (gettext("last-erred"));
418 case RCS_RESYNC:
419 return (gettext("resyncing"));
420 default:
421 return (gettext("unknown"));
422 }
423 }
424
425
426 /*
427 * meta_get_stripe_state()
428 *
429 * Gets the state for the underlying components of a stripe.
430 * This function is also called from: cmd/lvm/util/metastat.c.
431 *
432 * Returns:
433 * string for state of the stripe
434 *
435 */
436 char *
437 meta_get_stripe_state(
438 comp_state_t state
439 )
440 {
441 switch (state) {
442 case CS_OKAY:
443 return (NULL);
444 case CS_ERRED:
445 return (gettext("maint"));
446 case CS_LAST_ERRED:
447 return (gettext("last-erred"));
448 case CS_RESYNC:
449 return (gettext("resyncing"));
450 default:
451 return (gettext("invalid"));
452 }
453 }
454
455
456 /*
457 * meta_get_hs_state()
458 *
459 * Gets the state for the underlying components(hotspares) of a hotspare pool.
460 * This function is also called from: cmd/lvm/util/metastat.c.
461 *
462 * Returns:
463 * string for state of the hotspare
464 *
465 */
466 char *
467 meta_get_hs_state(
468 hotspare_states_t state
469 )
470 {
471 switch (state) {
472 case HSS_AVAILABLE:
473 return (NULL);
474 case HSS_RESERVED:
475 return (gettext("in-use"));
476 case HSS_BROKEN:
477 return (gettext("broken"));
478 case HSS_UNUSED:
479 /* FALLTHROUGH */
480 default:
481 return (gettext("invalid"));
482 }
483 }
484
485
486 /*
487 * process_trans()
488 *
489 * Prints unit information for a trans metadevice and calls the respective
490 * functions to process the underlying metadevices.
491 *
492 */
493 static void
494 process_trans(
495 md_im_rec_t **mdimpp,
496 int indent,
497 pnm_rec_t *phys_nm,
498 md_im_rec_t *mdrec
499 )
500 {
501 mt_unit_t *mt;
502 mdc_unit_t uc;
503 md_im_rec_t *tmpmdrec;
504 int underlying_device = PHYSICAL_DEV;
505
506 mt = (mt_unit_t *)mdrec->record;
507 uc = mt->c;
508
509 /* Printing name, size, and type of metadevice */
510 print_concise_entry(indent, mdrec->n_name,
511 uc.un_total_blocks, 't');
512
513 /*
514 * Loops through md_im_rec_t **mdimpp list of all metadevices to find
515 * record that matches the underlying device.
516 * Trans devices can only have one underlying device, so once a
517 * match is found, we are done.
518 */
519 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
520 tmpmdrec = tmpmdrec->next) {
521 if (tmpmdrec->n_key == mt->un_m_key) {
522 /* Printing name of the underlying metadevice */
523 (void) printf(" %s", tmpmdrec->n_name);
524 underlying_device = NOT_PHYSICAL_DEV;
525 break;
526 }
527 }
528
529 /*
530 * If a metadevice was not found, then the underlying device must be a
531 * physical device. Otherwise, call the functions to process the
532 * underlying devices.
533 */
534 if (underlying_device == PHYSICAL_DEV) {
535 print_physical_device(phys_nm, mt->un_m_key);
536 (void) printf("\n");
537 } else {
538 /* process underlying component */
539 (void) printf("\n");
540 indent += META_INDENT;
541 tmpmdrec->dfunc(mdimpp, indent, phys_nm, tmpmdrec);
542 }
543
544 /*
545 * Removing the md_entry from the list
546 * of all metadevices
547 */
548 free_mdrec_list_entry(&mdrec);
549 }
550
551
552 /*
553 * process_hotspare()
554 *
555 * Searches though list of physical devices to match hotspare record.
556 * Prints physical device name and state of a hotspare unit.
557 *
558 */
559 /*ARGSUSED*/
560 static void
561 process_hotspare(
562 md_im_rec_t **mdimpp,
563 int indent,
564 pnm_rec_t *phys_nm,
565 md_im_rec_t *mdrec
566 )
567 {
568 hot_spare_t *hs;
569 pnm_rec_t *tmpphys_nm;
570 char *state = NULL;
571
572 hs = (hot_spare_t *)mdrec->record;
573
574 /*
575 * Loops through physical namespace to find the device that matches
576 * the hotspare entry.
577 */
578 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
579 tmpphys_nm = tmpphys_nm->next) {
580 if (tmpphys_nm->n_key ==
581 ((hot_spare_t *)hs)->hs_key) {
582 /* Printing name of hotspare device */
583 (void) printf(" %s", tmpphys_nm->n_name);
584 break;
585 }
586 }
587
588 state = meta_get_hs_state(hs->hs_state);
589 if (state != NULL)
590 (void) printf(" (%s)", state);
591
592 /* Not removing entry, because it can be processed more than once. */
593 }
594
595
596 /*
597 * process_hotspare_pool()
598 *
599 * Prints concise unit information for a hotspare pool metadevice and calls a
600 * function to process each attached hotspare device.
601 *
602 */
603 static void
604 process_hotspare_pool(
605 md_im_rec_t **mdimpp,
606 int indent,
607 pnm_rec_t *phys_nm,
608 md_im_rec_t *mdrec
609 )
610 {
611 hot_spare_pool_ond_t *hsp;
612 int i;
613 md_im_rec_t *tmpmdrec;
614
615 hsp = (hot_spare_pool_ond_t *)mdrec->record;
616
617 /*
618 * Printing name, size, and type of metadevice. Setting size field to
619 * 0, so that output is the as metastat -c.
620 */
621 print_concise_entry(indent, mdrec->n_name,
622 0, 'h');
623
624 /* Looping through list of attached hotspare devices. */
625 for (i = 0; i < hsp->hsp_nhotspares; i++) {
626 /* Looking for the matching record for the hotspare device. */
627 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
628 tmpmdrec = tmpmdrec->next) {
629 if (tmpmdrec->hs_record_id == hsp->hsp_hotspares[i]) {
630 /* Calling function to print name of hotspare */
631 tmpmdrec->dfunc(mdimpp, indent, phys_nm,
632 tmpmdrec);
633 }
634 }
635 }
636 (void) printf("\n");
637
638 /*
639 * Removing the md_entry from the list
640 * of all metadevices
641 */
642 free_mdrec_list_entry(&mdrec);
643 }
644
645
646 /*
647 * process_raid()
648 *
649 * Prints concise unit information for a raid metadevice and calls the
650 * respective functions to process the underlying metadevices.
651 *
652 */
653 static void
654 process_raid(
655 md_im_rec_t **mdimpp,
656 int indent,
657 pnm_rec_t *phys_nm,
658 md_im_rec_t *mdrec
659 )
660 {
661 mr_unit_t *mr;
662 mr_column_t *mc;
663 mdc_unit_t uc;
664 int i;
665 md_im_rec_t *tmpmdrec;
666 md_im_rec_t *hstmpmdrec;
667 md_im_list_t *ucomp_head = NULL;
668 md_im_list_t *ucomp_tail = NULL;
669 md_im_list_t *ucomp = NULL;
670 pnm_rec_t *tmpphys_nm;
671 int underlying_device;
672
673 mr = (mr_unit_t *)mdrec->record;
674 uc = mr->c;
675
676 /* Printing name, size, and type of metadevice */
677 print_concise_entry(indent, mdrec->n_name,
678 uc.un_total_blocks, 'r');
679
680 /* Loops through raid columns to find underlying metadevices */
681 for (i = 0, mc = &mr->un_column[0]; i < mr->un_totalcolumncnt;
682 i++, mc++) {
683 char *state = NULL;
684 char *hsname = NULL;
685
686 /*
687 * Need to assume that underlying device is a physical device,
688 * unless we find a matching metadevice record.
689 */
690 underlying_device = PHYSICAL_DEV;
691
692 /*
693 * Loops through list of metadevices to find record that matches
694 * the underlying device.
695 */
696 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
697 tmpmdrec = tmpmdrec->next) {
698 if (tmpmdrec->n_key == mc->un_orig_key) {
699 /* check if hotspare device enabled */
700 if (mc->un_hs_id != NULL) {
701 /*
702 * Find matching metadevice record
703 * for the hotspare device.
704 */
705 for (hstmpmdrec = *mdimpp;
706 hstmpmdrec != NULL;
707 hstmpmdrec = hstmpmdrec->next) {
708 if (hstmpmdrec->hs_record_id ==
709 mc->un_hs_id) {
710 /* print name of hs */
711 hstmpmdrec->dfunc(
712 mdimpp, indent,
713 phys_nm,
714 hstmpmdrec);
715 break;
716 }
717 }
718 }
719 /* print name of underlying metadevice */
720 (void) printf(" %s", tmpmdrec->n_name);
721 underlying_device = NOT_PHYSICAL_DEV;
722 ucomp = Zalloc(sizeof (md_im_list_t));
723 ucomp->mdrec = tmpmdrec;
724 ucomponent_append(&ucomp_head, &ucomp_tail,
725 ucomp);
726 }
727 }
728
729 if (underlying_device == PHYSICAL_DEV) {
730 print_physical_device(phys_nm, mc->un_orig_key);
731 }
732 state = meta_get_raid_col_state(mc->un_devstate);
733
734 /*
735 * An underlying hotspare must be a physical device.
736 * If support is ever added for soft-partitions under
737 * hotspare pools, then this code should be updated to
738 * include a search for underlying metadevices.
739 */
740 if (mc->un_hs_id != 0) {
741 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
742 tmpphys_nm = tmpphys_nm->next) {
743 if (tmpphys_nm->n_key == mc->un_hs_key) {
744 hsname = tmpphys_nm->n_name;
745 break;
746 }
747 }
748 }
749
750 if (state != NULL) {
751 if (hsname != NULL)
752 (void) printf(" (%s-%s)", state,
753 hsname);
754 else
755 (void) printf(" (%s)", state);
756 } else if (hsname != NULL) {
757 (void) printf(gettext(" (spared-%s)"), hsname);
758 }
759 }
760 (void) printf("\n");
761
762 /* process underlying components */
763 indent += META_INDENT;
764 for (ucomp = ucomp_head; ucomp != NULL;
765 ucomp = ucomp->next) {
766 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
767 ucomp->mdrec);
768 }
769 free_md_im_list_entries(&ucomp_head);
770
771 /*
772 * Removing the md_entry from the list
773 * of all metadevices
774 */
775 free_mdrec_list_entry(&mdrec);
776 }
777
778
779 /*
780 * process_mirror()
781 *
782 * Prints concise unit information for a mirror metadevice and calls the
783 * respective functions to process the underlying metadevices.
784 *
785 */
786 static void
787 process_mirror(
788 md_im_rec_t **mdimpp,
789 int indent,
790 pnm_rec_t *phys_nm,
791 md_im_rec_t *mdrec
792 )
793 {
794 mm_unit_t *mm;
795 mm_submirror_t *sm;
796 mdc_unit_t uc;
797 int i;
798 md_im_rec_t *tmpmdrec;
799 md_im_list_t *ucomp_head = NULL;
800 md_im_list_t *ucomp_tail = NULL;
801 md_im_list_t *ucomp = NULL;
802
803 mm = (mm_unit_t *)mdrec->record;
804 uc = mm->c;
805
806 /* Printing name, size, and type of metadevice */
807 print_concise_entry(indent, mdrec->n_name,
808 uc.un_total_blocks, 'm');
809
810 /* Looping through sub-mirrors to find underlying devices */
811 for (i = 0, sm = &mm->un_sm[0]; i < mm->un_nsm; i++, sm++) {
812 char *state = NULL;
813
814 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
815 tmpmdrec = tmpmdrec->next) {
816 if (tmpmdrec->n_key == sm->sm_key) {
817 (void) printf(" %s", tmpmdrec->n_name);
818 ucomp = Zalloc(sizeof (md_im_list_t));
819 ucomp->mdrec = tmpmdrec;
820 ucomponent_append(&ucomp_head, &ucomp_tail,
821 ucomp);
822 }
823 }
824
825 /*
826 * It is not possible to have an underlying physical device
827 * for a submirror, so there is no need to search the phys_nm
828 * list.
829 */
830
831 /* Printing the state for the submirror */
832 state = meta_get_sm_state(sm->sm_state);
833 if (state != NULL) {
834 (void) printf(" (%s)", state);
835 }
836 }
837 (void) printf("\n");
838
839 /* process underlying components */
840 indent += META_INDENT;
841 for (ucomp = ucomp_head; ucomp != NULL;
842 ucomp = ucomp->next) {
843 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
844 ucomp->mdrec);
845 }
846 free_md_im_list_entries(&ucomp_head);
847
848 /*
849 * Removing the md_entry from the list
850 * of all metadevices
851 */
852 free_mdrec_list_entry(&mdrec);
853 }
854
855
856 /*
857 * process_stripe()
858 *
859 * Prints concise unit information for a stripe metadevice and calls the
860 * respective functions to process the underlying metadevices.
861 *
862 */
863 static void
864 process_stripe(
865 md_im_rec_t **mdimpp,
866 int indent,
867 pnm_rec_t *phys_nm,
868 md_im_rec_t *mdrec
869 )
870 {
871 ms_unit_t *ms;
872 mdc_unit_t uc;
873 md_im_rec_t *tmpmdrec;
874 md_im_list_t *ucomp_head = NULL;
875 md_im_list_t *ucomp_tail = NULL;
876 md_im_list_t *ucomp = NULL;
877 pnm_rec_t *tmpphys_nm;
878 int underlying_device;
879 uint_t row;
880
881 ms = (ms_unit_t *)mdrec->record;
882 uc = ms->c;
883
884 /* Printing name, size, and type of metadevice */
885 print_concise_entry(indent, mdrec->n_name,
886 uc.un_total_blocks, 's');
887
888 /* Looping through stripe rows */
889 for (row = 0; (row < ms->un_nrows); ++row) {
890 struct ms_row *mdr = &ms->un_row[row];
891 ms_comp_t *mdcomp = (void *)&((char *)ms)
892 [ms->un_ocomp];
893 uint_t comp, c;
894
895 /*
896 * Looping through the components in each row to find the
897 * underlying devices.
898 */
899 for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp);
900 ++comp, ++c) {
901 char *state = NULL;
902 char *hsname = NULL;
903 ms_comp_t *mdc = &mdcomp[c];
904 md_m_shared_t *mdm = &mdc->un_mirror;
905
906 /*
907 * Need to assume that underlying device is a
908 * physical device, unless we find a matching
909 * metadevice record.
910 */
911 underlying_device = PHYSICAL_DEV;
912
913 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
914 tmpmdrec = tmpmdrec->next) {
915 if (tmpmdrec->n_key == mdc->un_key) {
916 (void) printf(" %s", tmpmdrec->n_name);
917 underlying_device = NOT_PHYSICAL_DEV;
918 ucomp = Zalloc(sizeof (md_im_list_t));
919 ucomp->mdrec = tmpmdrec;
920 ucomponent_append(&ucomp_head,
921 &ucomp_tail, ucomp);
922 }
923 }
924 /* if an underlying metadevice was not found */
925 if (underlying_device == PHYSICAL_DEV) {
926 print_physical_device(phys_nm, mdc->un_key);
927 }
928 state = meta_get_stripe_state(mdm->ms_state);
929
930 /*
931 * An underlying hotspare must be a physical device.
932 * If support is ever added for soft-partitions under
933 * hotspare pools, then this code should be updated to
934 * include a search for underlying metadevices.
935 */
936 if (mdm->ms_hs_key != 0) {
937 for (tmpphys_nm = phys_nm; tmpphys_nm != NULL;
938 tmpphys_nm = tmpphys_nm->next) {
939 if (tmpphys_nm->n_key ==
940 mdm->ms_hs_key) {
941 hsname = tmpphys_nm->n_name;
942 break;
943 }
944 }
945 }
946 if (state != NULL) {
947 if (hsname != NULL) {
948 (void) printf(" (%s-%s)", state,
949 hsname);
950 } else {
951 (void) printf(" (%s)", state);
952 }
953 } else if (hsname != NULL) {
954 (void) printf(gettext(" (spared-%s)"), hsname);
955 }
956 }
957 }
958 (void) printf("\n");
959
960 /* Process underlying metadevices */
961 indent += META_INDENT;
962 for (ucomp = ucomp_head; ucomp != NULL;
963 ucomp = ucomp->next) {
964 ucomp->mdrec->dfunc(mdimpp, indent, phys_nm,
965 ucomp->mdrec);
966 }
967 free_md_im_list_entries(&ucomp_head);
968
969 /*
970 * Removing the md_entry from the list
971 * of all metadevices
972 */
973 free_mdrec_list_entry(&mdrec);
974 }
975
976
977 /*
978 * process_softpart()
979 *
980 * Prints concise unit information for a softpart metadevice and calls the
981 * respective functions to process the underlying metadevices.
982 *
983 */
984 static void
985 process_softpart(
986 md_im_rec_t **mdimpp,
987 int indent,
988 pnm_rec_t *phys_nm,
989 md_im_rec_t *mdrec
990 )
991 {
992 mp_unit_t *mp;
993 mdc_unit_t uc;
994 md_im_rec_t *tmpmdrec;
995 int underlying_device = PHYSICAL_DEV;
996
997 mp = (mp_unit_t *)mdrec->record;
998 uc = mp->c;
999
1000 /* Printing name, size, and type of metadevice */
1001 print_concise_entry(indent, mdrec->n_name,
1002 uc.un_total_blocks, 'p');
1003
1004 /*
1005 * Loops through md_im_rec_t **mdimpp list of all metadevices to find
1006 * record that matches the underlying device.
1007 * Softpartitions can only have one underlying device, so once a
1008 * match is found, we are done.
1009 */
1010 for (tmpmdrec = *mdimpp; tmpmdrec != NULL;
1011 tmpmdrec = tmpmdrec->next) {
1012 if (tmpmdrec->n_key == mp->un_key) {
1013 /* Printing name of the underlying metadevice */
1014 (void) printf(" %s", tmpmdrec->n_name);
1015 underlying_device = NOT_PHYSICAL_DEV;
1016 break;
1017 }
1018 }
1019
1020 /* This is only executed if an underlying metadevice was not found */
1021 if (underlying_device == PHYSICAL_DEV) {
1022 print_physical_device(phys_nm, mp->un_key);
1023 (void) printf("\n");
1024 } else {
1025 /* Process underlying metadevice */
1026 (void) printf("\n");
1027 indent += META_INDENT;
1028 tmpmdrec->dfunc(mdimpp, indent, phys_nm,
1029 tmpmdrec);
1030 }
1031
1032 /*
1033 * Removing the md_entry from the list
1034 * of all metadevices
1035 */
1036 free_mdrec_list_entry(&mdrec);
1037 }
1038
1039
1040 /*
1041 * process_toplevel_softparts()
1042 *
1043 * Toplevel softpartions need to be grouped so that their underlying devices
1044 * can be printed just once.
1045 */
1046 static void
1047 process_toplevel_softparts(
1048 md_im_rec_t **mdimpp,
1049 int indent,
1050 pnm_rec_t *phys_nm
1051 )
1052 {
1053 mp_unit_t *mp;
1054 mdc_unit_t uc;
1055 md_im_rec_t *mdrec;
1056 md_im_rec_t *comp_mdrec; /* pntr to underlying component's record */
1057 md_im_rec_t *tmp_mdrec, *rm_mdrec;
1058 mp_unit_t *tmp_mp;
1059 int underlying_device;
1060
1061 /*
1062 * Loops through md_im_rec_t **mdimpp list of all metadevices to find
1063 * all softpartions that are toplevel softpartitions(softparts w/out
1064 * a parent). Groups output for these entries so that the function to
1065 * process the underlying metadevice is only called once.
1066 */
1067 for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) {
1068
1069 underlying_device = PHYSICAL_DEV;
1070 if ((mdrec->md_type == MDDB_F_SOFTPART) &&
1071 (mdrec->has_parent == 0)) {
1072 mp = (mp_unit_t *)mdrec->record;
1073 uc = mp->c;
1074 /* Printing name, size, and type of metadevice */
1075 print_concise_entry(indent, mdrec->n_name,
1076 uc.un_total_blocks, 'p');
1077 /*
1078 * Looking for record that matches underlying
1079 * component.
1080 */
1081 for (comp_mdrec = *mdimpp; comp_mdrec != NULL;
1082 comp_mdrec = comp_mdrec->next) {
1083 if (comp_mdrec->n_key == mp->un_key) {
1084 /* Print name of underlying device */
1085 (void) printf(" %s",
1086 comp_mdrec->n_name);
1087 underlying_device = NOT_PHYSICAL_DEV;
1088 break;
1089 }
1090 }
1091 if (underlying_device == PHYSICAL_DEV) {
1092 print_physical_device(phys_nm, mp->un_key);
1093 }
1094 (void) printf("\n");
1095
1096 /*
1097 * Looking for any other toplevel softpartitions with
1098 * same underlying device. We know that all other
1099 * matching metadevices, that share the same underlying
1100 * metadevice, are also soft-partitions.
1101 */
1102 for (tmp_mdrec = mdrec->next; tmp_mdrec != NULL; ) {
1103 tmp_mp = (mp_unit_t *)tmp_mdrec->record;
1104 if ((tmp_mdrec->has_parent == 0) &&
1105 (tmp_mp->un_key == mp->un_key)) {
1106 uc = tmp_mp->c;
1107 print_concise_entry(indent,
1108 tmp_mdrec->n_name,
1109 uc.un_total_blocks, 'p');
1110 if (underlying_device ==
1111 NOT_PHYSICAL_DEV) {
1112 (void) printf(" %s",
1113 comp_mdrec->n_name);
1114 } else {
1115 print_physical_device(
1116 phys_nm, tmp_mp->un_key);
1117 }
1118 (void) printf("\n");
1119 /*
1120 * Need to advance so that will not lose
1121 * position after removing processed
1122 * record.
1123 */
1124 rm_mdrec = tmp_mdrec;
1125 tmp_mdrec = tmp_mdrec->next;
1126 /*
1127 * Removing the md_entry from the list
1128 * of all metadevices.
1129 */
1130 free_mdrec_list_entry(&rm_mdrec);
1131 } else {
1132 tmp_mdrec = tmp_mdrec->next;
1133 }
1134 }
1135 /* Process the underlying device */
1136 if (underlying_device == NOT_PHYSICAL_DEV) {
1137 indent += META_INDENT;
1138 comp_mdrec->dfunc(mdimpp, indent, phys_nm,
1139 comp_mdrec);
1140 }
1141 }
1142 }
1143 }
1144
1145
1146 /*
1147 * process_toplevel_devices()
1148 *
1149 * Search through list of metadevices for metadevices of md_type that do not
1150 * have a parent.
1151 *
1152 */
1153 static void
1154 process_toplevel_devices(
1155 md_im_rec_t **mdimpp,
1156 pnm_rec_t *pnm,
1157 uint_t md_type
1158 )
1159 {
1160 md_im_rec_t *mdrec;
1161 md_im_list_t *mdrec_tl_tail = NULL;
1162 md_im_list_t *mdrec_tl_head = NULL;
1163 md_im_list_t *tmp_tl_list = NULL;
1164 int indent = 0;
1165
1166 indent += META_INDENT;
1167
1168 /*
1169 * Need to group soft partitions so that common underlying device
1170 * are only processed once.
1171 */
1172 if (md_type == MDDB_F_SOFTPART) {
1173 process_toplevel_softparts(mdimpp, indent, pnm);
1174 return;
1175 }
1176
1177 /*
1178 * Search the list of metadevices to find all metadevices that match
1179 * the type and don't have a parent. Put them on a separate list
1180 * that will be processed.
1181 */
1182 for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) {
1183 if ((mdrec->md_type == md_type)&&(mdrec->has_parent == 0)) {
1184 tmp_tl_list = Zalloc(sizeof (md_im_list_t));
1185 tmp_tl_list->mdrec = mdrec;
1186 tmp_tl_list->next = NULL;
1187 if (mdrec_tl_tail == NULL) {
1188 mdrec_tl_tail = tmp_tl_list;
1189 mdrec_tl_head = mdrec_tl_tail;
1190 } else {
1191 mdrec_tl_tail->next = tmp_tl_list;
1192 mdrec_tl_tail = mdrec_tl_tail->next;
1193 }
1194 }
1195
1196 }
1197
1198 /*
1199 * Loop through list and process all top-level metadevices of a
1200 * given type.
1201 */
1202 for (tmp_tl_list = mdrec_tl_head; tmp_tl_list != NULL;
1203 tmp_tl_list = tmp_tl_list->next) {
1204 tmp_tl_list->mdrec->dfunc(mdimpp, indent, pnm,
1205 tmp_tl_list->mdrec);
1206 }
1207
1208 free_md_im_list_entries(&mdrec_tl_head);
1209 }
1210
1211
1212 /*
1213 * extract_mduser_data()
1214 *
1215 * Converts or copies the (mddb_rb_t->rb_data) metadevice record to a 64bit
1216 * record.
1217 * Sets the dfunc field to point to the appropriate function to process the
1218 * metadevice.
1219 * Sets the parent field for the metadevice.
1220 * Extracts the name from the NM namespace if it is available, otherwise
1221 * generates it from the metadevice's minor number.
1222 *
1223 * Returns:
1224 * < 0 for failure
1225 * 0 for success
1226 *
1227 */
1228 static int
1229 extract_mduser_data(
1230 mddb_rb_t *nm,
1231 md_im_rec_t *mdrec,
1232 void *rbp,
1233 int is_32bit_record,
1234 md_error_t *ep
1235 )
1236 {
1237 mdc_unit_t uc;
1238 hot_spare_t *hs;
1239 hot_spare_pool_ond_t *hsp;
1240 size_t newreqsize;
1241 mddb_rb_t *rbp_nm = nm;
1242 struct nm_rec *nm_record;
1243 struct nm_name *nmname;
1244 char *uname = NULL;
1245
1246
1247 /*LINTED*/
1248 nm_record = (struct nm_rec *)((caddr_t)(&rbp_nm->rb_data));
1249
1250 /*
1251 * Setting the un_self_id or the hs_self_id, in the case of hotspare
1252 * records, for each metadevice entry. Also setting has_parent and
1253 * setting dfunc so that it points to the correct function to process
1254 * the record type.
1255 * If the record was stored ondisk in 32bit format, then it is
1256 * converted to the 64bits equivalent 64bit format and the memory
1257 * for the 32bit pointer is freed.
1258 */
1259 switch (mdrec->md_type) {
1260 case MDDB_F_SOFTPART:
1261 if (is_32bit_record) {
1262 mp_unit32_od_t *small_un;
1263 mp_unit_t *big_un;
1264
1265 small_un = (mp_unit32_od_t *)((uintptr_t)rbp +
1266 (sizeof (mddb_rb_t) - sizeof (int)));
1267 newreqsize = sizeof (mp_unit_t) +
1268 ((small_un->un_numexts - 1) *
1269 sizeof (struct mp_ext));
1270 big_un = (void *)Zalloc(newreqsize);
1271 softpart_convert((caddr_t)small_un,
1272 (caddr_t)big_un, SMALL_2_BIG);
1273 mdrec->record = (void *)big_un;
1274 } else {
1275 mp_unit_t *big_un;
1276
1277 big_un = (mp_unit_t *)((uintptr_t)rbp +
1278 (sizeof (mddb_rb_t) - sizeof (int)));
1279 newreqsize = sizeof (mp_unit_t) +
1280 ((big_un->un_numexts - 1) *
1281 sizeof (struct mp_ext));
1282 mdrec->record = (void *)Zalloc(newreqsize);
1283 bcopy(big_un, mdrec->record, newreqsize);
1284 }
1285 uc = ((mp_unit_t *)mdrec->record)->c;
1286 mdrec->dfunc = &process_softpart;
1287 mdrec->un_self_id = uc.un_self_id;
1288 mdrec->has_parent = MD_HAS_PARENT(
1289 uc.un_parent);
1290 break;
1291 case MDDB_F_STRIPE:
1292 if (is_32bit_record) {
1293 ms_unit32_od_t *small_un;
1294 ms_unit_t *big_un;
1295
1296 small_un = (ms_unit32_od_t *)((uintptr_t)rbp +
1297 (sizeof (mddb_rb_t) - sizeof (int)));
1298 newreqsize = get_big_stripe_req_size(
1299 small_un, COMPLETE_STRUCTURE);
1300 big_un = (void *)Zalloc(newreqsize);
1301 stripe_convert((caddr_t)small_un,
1302 (caddr_t)big_un, SMALL_2_BIG);
1303 mdrec->record = (void *)big_un;
1304 } else {
1305 ms_unit_t *big_un;
1306
1307 big_un = (ms_unit_t *)((uintptr_t)rbp +
1308 (sizeof (mddb_rb_t) - sizeof (int)));
1309 newreqsize = get_stripe_req_size(big_un);
1310 mdrec->record = (void *)Zalloc(newreqsize);
1311 bcopy(big_un, mdrec->record, newreqsize);
1312 }
1313 uc = ((ms_unit_t *)mdrec->record)->c;
1314 mdrec->dfunc = &process_stripe;
1315 mdrec->un_self_id = uc.un_self_id;
1316 mdrec->has_parent = MD_HAS_PARENT(
1317 uc.un_parent);
1318 break;
1319 case MDDB_F_MIRROR:
1320 if (is_32bit_record) {
1321 mm_unit32_od_t *small_un;
1322 mm_unit_t *big_un;
1323
1324 small_un = (mm_unit32_od_t *)((uintptr_t)rbp +
1325 (sizeof (mddb_rb_t) - sizeof (int)));
1326 newreqsize = sizeof (mm_unit_t);
1327 big_un = (void *)Zalloc(newreqsize);
1328 mirror_convert((caddr_t)small_un,
1329 (caddr_t)big_un, SMALL_2_BIG);
1330 mdrec->record = (void *)big_un;
1331 } else {
1332 mm_unit_t *big_un;
1333
1334 big_un = (mm_unit_t *)((uintptr_t)rbp +
1335 (sizeof (mddb_rb_t) - sizeof (int)));
1336 newreqsize = sizeof (mm_unit_t);
1337 mdrec->record = (void *)Zalloc(newreqsize);
1338 bcopy(big_un, mdrec->record, newreqsize);
1339 }
1340 uc = ((mm_unit_t *)mdrec->record)->c;
1341 mdrec->dfunc = &process_mirror;
1342 mdrec->un_self_id = uc.un_self_id;
1343 mdrec->has_parent = MD_HAS_PARENT(
1344 uc.un_parent);
1345 break;
1346 case MDDB_F_RAID:
1347 if (is_32bit_record) {
1348 mr_unit32_od_t *small_un;
1349 mr_unit_t *big_un;
1350 uint_t ncol;
1351
1352 small_un = (mr_unit32_od_t *)((uintptr_t)rbp +
1353 (sizeof (mddb_rb_t) - sizeof (int)));
1354 ncol = small_un->un_totalcolumncnt;
1355 newreqsize = sizeof (mr_unit_t) +
1356 ((ncol - 1) * sizeof (mr_column_t));
1357 big_un = (void *)Zalloc(newreqsize);
1358 raid_convert((caddr_t)small_un,
1359 (caddr_t)big_un, SMALL_2_BIG);
1360 mdrec->record = (void *)big_un;
1361 } else {
1362 mr_unit_t *big_un;
1363 uint_t ncol;
1364
1365 big_un = (mr_unit_t *)((uintptr_t)rbp +
1366 (sizeof (mddb_rb_t) - sizeof (int)));
1367 ncol = big_un->un_totalcolumncnt;
1368 newreqsize = sizeof (mr_unit_t) +
1369 ((ncol - 1) * sizeof (mr_column_t));
1370 mdrec->record = (void *)Zalloc(newreqsize);
1371 bcopy(big_un, mdrec->record, newreqsize);
1372 }
1373 uc = ((mr_unit_t *)mdrec->record)->c;
1374 mdrec->dfunc = &process_raid;
1375 mdrec->un_self_id = uc.un_self_id;
1376 mdrec->has_parent = MD_HAS_PARENT(
1377 uc.un_parent);
1378 break;
1379 case MDDB_F_TRANS_MASTER:
1380 if (is_32bit_record) {
1381 mt_unit32_od_t *small_un;
1382 mt_unit_t *big_un;
1383
1384 small_un = (mt_unit32_od_t *)((uintptr_t)rbp +
1385 (sizeof (mddb_rb_t) - sizeof (int)));
1386 newreqsize = sizeof (mt_unit_t);
1387 big_un = (void *)Zalloc(newreqsize);
1388 trans_master_convert((caddr_t)small_un,
1389 (caddr_t)big_un, SMALL_2_BIG);
1390 mdrec->record = (void *)big_un;
1391 } else {
1392 mt_unit_t *big_un;
1393
1394 big_un = (mt_unit_t *)((uintptr_t)rbp +
1395 (sizeof (mddb_rb_t) - sizeof (int)));
1396 newreqsize = sizeof (mt_unit_t);
1397 mdrec->record = (void *)Zalloc(newreqsize);
1398 bcopy(big_un, mdrec->record, newreqsize);
1399 }
1400 uc = ((mt_unit_t *)mdrec->record)->c;
1401 mdrec->dfunc = &process_trans;
1402 mdrec->un_self_id = uc.un_self_id;
1403 mdrec->has_parent = MD_HAS_PARENT(
1404 uc.un_parent);
1405 break;
1406 case MDDB_F_HOTSPARE:
1407 if (is_32bit_record) {
1408 hot_spare32_od_t *small_un;
1409 hot_spare_t *big_un;
1410
1411 small_un = (hot_spare32_od_t *)((uintptr_t)rbp +
1412 (sizeof (mddb_rb_t) - sizeof (int)));
1413 newreqsize = sizeof (hot_spare_t);
1414 big_un = (void *)Zalloc(newreqsize);
1415 hs_convert((caddr_t)small_un,
1416 (caddr_t)big_un, SMALL_2_BIG);
1417 mdrec->record = (void *)big_un;
1418 } else {
1419 hot_spare_t *big_un;
1420
1421 big_un = (hot_spare_t *)((uintptr_t)rbp +
1422 (sizeof (mddb_rb_t) - sizeof (int)));
1423 newreqsize = sizeof (hot_spare_t);
1424 mdrec->record = (void *)Zalloc(newreqsize);
1425 bcopy(big_un, mdrec->record, newreqsize);
1426 }
1427 hs = (hot_spare_t *)mdrec->record;
1428 mdrec->dfunc = &process_hotspare;
1429 mdrec->un_self_id = NULL;
1430 mdrec->hs_record_id = hs->hs_record_id;
1431 mdrec->has_parent = 1;
1432 break;
1433 case MDDB_F_HOTSPARE_POOL:
1434 /*
1435 * Ondisk and incore records are always same size.
1436 */
1437 hsp = (hot_spare_pool_ond_t *)((uintptr_t)rbp +
1438 (sizeof (mddb_rb_t) - sizeof (int)));
1439 newreqsize = sizeof (hot_spare_pool_ond_t) +
1440 (sizeof (mddb_recid_t) * hsp->hsp_nhotspares);
1441 mdrec->record = (void *)Zalloc(newreqsize);
1442 bcopy(hsp, mdrec->record, newreqsize);
1443 hsp = (hot_spare_pool_ond_t *)mdrec->record;
1444 mdrec->dfunc = &process_hotspare_pool;
1445 /*
1446 * If the hsp has descriptive name we'll get
1447 * the un_self_id
1448 */
1449 if (HSP_ID_IS_FN(hsp->hsp_self_id))
1450 mdrec->un_self_id = hsp->hsp_self_id;
1451 else
1452 mdrec->un_self_id = NULL;
1453 mdrec->has_parent = 0;
1454 break;
1455 /* All valid cases have been dealt with */
1456 default:
1457 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1458 return (-1);
1459 }
1460
1461 /*
1462 * If metadevice record has an entry in the NM namespace
1463 * then it is copied into the mdrec->n_name field.
1464 */
1465 if (mdrec->un_self_id != NULL) {
1466 for (nmname = &nm_record->r_name[0]; nmname->n_key != 0;
1467 /*LINTED*/
1468 nmname = (struct nm_name *)((char *)nmname +
1469 NAMSIZ(nmname))) {
1470 /*
1471 * Extract the metadevice/hsp name if it is
1472 * in the namespace.
1473 *
1474 * If it is a hot spare pool we will find our
1475 * match by comparing the NM record's n_key
1476 * with the extracted key from the hsp_self_id
1477 * Else, match the un_self_id for the record
1478 * to the n_minor name in the NM record.
1479 */
1480 if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) {
1481 if (nmname->n_key ==
1482 HSP_ID_TO_KEY(hsp->hsp_self_id)) {
1483 mdrec->n_key = nmname->n_key;
1484 uname = Strdup(nmname->n_name);
1485 mdrec->n_name = uname;
1486 break;
1487 }
1488 } else {
1489 if ((nmname->n_minor) == (uc.un_self_id)) {
1490 (*mdrec).n_key = nmname->n_key;
1491 uname = Strdup(nmname->n_name);
1492 mdrec->n_name = uname;
1493 break;
1494 }
1495 }
1496 }
1497 }
1498
1499 /*
1500 * If the metadevice name is not in the namespace, then
1501 * then we will generate the name from the minor number
1502 * for the metadevice. In the case of records for a hotspare
1503 * pool we use hsp_self_id, otherwise we use un_self_id.
1504 */
1505 if (uname == NULL) {
1506 if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) {
1507 uname = Malloc(MAXSIZEMDRECNAME);
1508 (void) sprintf(uname, "hsp%03u",
1509 HSP_ID(hsp->hsp_self_id));
1510 mdrec->n_name = uname;
1511 } else if (mdrec->md_type != MDDB_F_HOTSPARE) {
1512 /*
1513 * Generate the metadevice name for all other records
1514 * (except for hotspares, because hotspares can only
1515 * be physical devices.)
1516 */
1517 uname = Malloc(MAXSIZEMDRECNAME);
1518 (void) sprintf(uname, "d%lu",
1519 MD_MIN2UNIT(mdrec->un_self_id));
1520 mdrec->n_name = uname;
1521 }
1522 }
1523
1524 return (0);
1525 }
1526
1527
1528 /*
1529 * read_mdrecord()
1530 *
1531 * Reads the mddb_rb32_od_t or mddb_rb_t and the associated metadevice record
1532 * from the disk. Runs magic, checksum, and revision checks on the record
1533 * block.
1534 *
1535 * Returns:
1536 * < 0 for failure
1537 * 0 for success
1538 *
1539 */
1540 static int
1541 read_mdrecord(
1542 md_im_rec_t **mdimpp,
1543 mddb_mb_t *mbp,
1544 mddb_rb_t *nm,
1545 mddb_de_t *dep,
1546 char *diskname,
1547 int fd,
1548 md_timeval32_t *lastaccess,
1549 md_error_t *ep
1550 )
1551 {
1552 int cnt, rval = 0;
1553 daddr_t pblk;
1554 md_im_rec_t *tmp_mdrec;
1555 void *rbp = NULL;
1556 char *rbp_tmp = NULL;
1557 mddb_rb32_t *rbp_32;
1558 mddb_rb_t *rbp_64;
1559 crc_skip_t *skip = NULL;
1560 int is_32bit_record;
1561
1562 tmp_mdrec = Zalloc(sizeof (md_im_rec_t));
1563 rbp = (void *)Zalloc(dbtob(dep->de_blkcount));
1564 rbp_tmp = (char *)rbp;
1565
1566 /* Read in the appropriate record and return configurations */
1567 for (cnt = 0; cnt < dep->de_blkcount; cnt++) {
1568 if ((pblk = getphysblk(dep->de_blks[cnt], mbp)) < 0) {
1569 rval = mdmddberror(ep, MDE_DB_BLKRANGE,
1570 NODEV32, MD_LOCAL_SET,
1571 dep->de_blks[cnt], diskname);
1572 return (rval);
1573 }
1574
1575 if (lseek(fd, (off_t)dbtob(pblk), SEEK_SET) < 0) {
1576 rval = mdsyserror(ep, errno, diskname);
1577 return (rval);
1578 }
1579
1580 if (read(fd, rbp_tmp, DEV_BSIZE) != DEV_BSIZE) {
1581 rval = mdsyserror(ep, errno, diskname);
1582 return (rval);
1583 }
1584
1585 rbp_tmp += DEV_BSIZE;
1586 }
1587 tmp_mdrec->md_type = dep->de_flags;
1588
1589 /*
1590 * The only place to discover whether or not the record is a
1591 * 32bit or 64bit record is from the record's rb_revision field.
1592 * The mddb_rb_t and mddb_rb32_t structures are identical for the
1593 * following fields:
1594 * rb_magic, rb_revision, rb_checksum, and rb_checksum_fiddle.
1595 * So we can assume that the record is a 32bit structure when we
1596 * check the record's magic number and revision and when we calculate
1597 * the records checksum.
1598 */
1599 rbp_32 = (mddb_rb32_t *)rbp;
1600
1601 /*
1602 * Checking the magic number for the record block.
1603 */
1604 if (rbp_32->rb_magic != MDDB_MAGIC_RB) {
1605 rval = -1;
1606 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1607 goto out;
1608 }
1609
1610 /*
1611 * Checking the revision for the record block. Must match either
1612 * revision for the current 64bit or 32bit record block. Also,
1613 * setting the flag for whether or not it is a 32bit record.
1614 */
1615 is_32bit_record = 0;
1616 switch (rbp_32->rb_revision) {
1617 case MDDB_REV_RB:
1618 case MDDB_REV_RBFN:
1619 is_32bit_record = 1;
1620 break;
1621 case MDDB_REV_RB64:
1622 case MDDB_REV_RB64FN:
1623 break;
1624 default:
1625 rval = -1;
1626 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1627 goto out;
1628 }
1629
1630 /*
1631 * Calculating the checksum for this record block. Need
1632 * to skip the rb's checksum fiddle.
1633 */
1634 skip = (crc_skip_t *)Malloc(sizeof (crc_skip_t));
1635 skip->skip_next = NULL;
1636 skip->skip_offset = offsetof(mddb_rb_t, rb_checksum_fiddle);
1637 skip->skip_size = 3 * sizeof (uint_t);
1638 if (crcchk(rbp_32, &rbp_32->rb_checksum, dep->de_recsize, skip)) {
1639 rval = -1;
1640 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1641 goto out;
1642 }
1643
1644 /* mddb_rb_t and mddb_rb32_t differ before the rb_timestamp field */
1645 if (!is_32bit_record) {
1646 if ((*lastaccess).tv_sec < rbp_32->rb_timestamp.tv_sec) {
1647 *lastaccess = rbp_32->rb_timestamp;
1648 } else if ((*lastaccess).tv_sec ==
1649 rbp_32->rb_timestamp.tv_sec) {
1650 if ((*lastaccess).tv_usec <
1651 rbp_32->rb_timestamp.tv_usec)
1652 *lastaccess = rbp_32->rb_timestamp;
1653 }
1654 } else {
1655 rbp_64 = (mddb_rb_t *)rbp;
1656 if ((*lastaccess).tv_sec < rbp_64->rb_timestamp.tv_sec) {
1657 *lastaccess = rbp_64->rb_timestamp;
1658 } else if ((*lastaccess).tv_sec ==
1659 rbp_64->rb_timestamp.tv_sec) {
1660 if ((*lastaccess).tv_usec <
1661 rbp_64->rb_timestamp.tv_usec)
1662 *lastaccess = rbp_64->rb_timestamp;
1663 }
1664 }
1665
1666 /* Populates the fields in md_im_rec_t *tmp_mdrec. */
1667 rval = extract_mduser_data(nm, tmp_mdrec, rbp, is_32bit_record, ep);
1668 if (rval < 0)
1669 goto out;
1670
1671 /* Adding record to the head of the list of all metadevices. */
1672 tmp_mdrec->prev = NULL;
1673 if (*mdimpp == NULL) {
1674 tmp_mdrec->next = NULL;
1675 *mdimpp = tmp_mdrec;
1676 } else {
1677 (*mdimpp)->prev = tmp_mdrec;
1678 tmp_mdrec->next = *mdimpp;
1679 *mdimpp = tmp_mdrec;
1680 }
1681
1682 out:
1683 /* Free the skip list */
1684 while (skip) {
1685 crc_skip_t *skip_rm = skip;
1686
1687 skip = skip->skip_next;
1688 Free(skip_rm);
1689 }
1690
1691 if (rbp)
1692 Free(rbp);
1693
1694 return (rval);
1695 }
1696
1697
1698 /*
1699 * read_all_mdrecords()
1700 *
1701 * Reads the directory block and directory entries.
1702 * Runs magic, checksum, and revision checks on the directory block.
1703 *
1704 * Returns:
1705 * < 0 for failure
1706 * 0 for success
1707 */
1708 static int
1709 read_all_mdrecords(
1710 md_im_rec_t **mdimpp,
1711 mddb_mb_t *mbp,
1712 mddb_lb_t *lbp,
1713 mddb_rb_t *nm,
1714 mdname_t *rsp,
1715 int fd,
1716 md_timeval32_t *lastaccess,
1717 md_error_t *ep
1718 )
1719 {
1720 int dbblk, rval = 0;
1721 char db[DEV_BSIZE];
1722 mddb_de_t *dep;
1723 int desize;
1724 /*LINTED*/
1725 mddb_db_t *dbp = (mddb_db_t *)&db;
1726
1727 /* Read in all directory blocks */
1728 for (dbblk = lbp->lb_dbfirstblk;
1729 dbblk != 0;
1730 dbblk = dbp->db_nextblk) {
1731
1732 if ((rval = read_database_block(ep, fd, mbp, dbblk,
1733 dbp, sizeof (db))) <= 0)
1734 goto out;
1735
1736 /*
1737 * Set ep with error code for MDE_DB_NODB. This is the
1738 * error code used in the kernel when there is a problem
1739 * with reading records in. Checks the magic number, the
1740 * revision, and the checksum for each directory block.
1741 */
1742 if (dbp->db_magic != MDDB_MAGIC_DB) {
1743 rval = -1;
1744 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1745 goto out;
1746 }
1747
1748 if (revchk(MDDB_REV_DB, dbp->db_revision)) {
1749 rval = -1;
1750 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1751 goto out;
1752 }
1753
1754 if (crcchk(dbp, &dbp->db_checksum, MDDB_BSIZE, NULL)) {
1755 rval = -1;
1756 (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL);
1757 goto out;
1758 }
1759
1760 /*
1761 * If db timestamp is more recent than the previously recorded
1762 * last modified timestamp, then update last modified.
1763 */
1764 if ((*lastaccess).tv_sec < dbp->db_timestamp.tv_sec) {
1765 *lastaccess = dbp->db_timestamp;
1766 } else if ((*lastaccess).tv_sec == dbp->db_timestamp.tv_sec) {
1767 if ((*lastaccess).tv_usec < dbp->db_timestamp.tv_usec)
1768 *lastaccess = dbp->db_timestamp;
1769 }
1770
1771 /* Creates dep list of all directory entries in the db */
1772 if (dbp->db_firstentry != NULL) {
1773 /* LINTED */
1774 dep = (mddb_de_t *)((caddr_t)(&dbp->db_firstentry)
1775 + sizeof (dbp->db_firstentry));
1776 dbp->db_firstentry = dep;
1777 while (dep && dep->de_next) {
1778 desize = sizeof (*dep) -
1779 sizeof (dep->de_blks) +
1780 sizeof (daddr_t) * dep->de_blkcount;
1781 /* LINTED */
1782 dep->de_next = (mddb_de_t *)
1783 ((caddr_t)dep + desize);
1784 dep = dep->de_next;
1785 }
1786 }
1787
1788 /*
1789 * Process all directory entries in the directory block.
1790 * For each directory entry, read_mdrec is called to read
1791 * in the record data.
1792 */
1793 for (dep = dbp->db_firstentry; dep != NULL;
1794 dep = dep->de_next) {
1795
1796 /*
1797 * de_flags is set to the type of metadevice.
1798 * If directory entry does not correspond to a
1799 * specific metadevice then it is set to zero.
1800 * All namespace records(NM, SHR_NM, DID_SHR_NM) have a
1801 * value of zero in their de_flags field.
1802 */
1803 if ((dep->de_flags != 0)&&
1804 (dep->de_flags != MDDB_F_OPT) &&
1805 (dep->de_flags != MDDB_F_TRANS_LOG) &&
1806 (dep->de_flags != MDDB_F_CHANGELOG)) {
1807 rval = read_mdrecord(mdimpp, mbp, nm, dep,
1808 rsp->cname, fd, lastaccess, ep);
1809 if (rval < 0)
1810 goto out;
1811 }
1812 }
1813 }
1814
1815 out:
1816 return (rval);
1817 }
1818
1819
1820 /*
1821 * report_metastat_info()
1822 *
1823 * Generates the metastat -c output. Also, updates the global variable
1824 * for a last accessed timestamp.
1825 *
1826 * Returns:
1827 * < 0 for failure
1828 * 0 for success
1829 *
1830 */
1831 int
1832 report_metastat_info(
1833 mddb_mb_t *mb,
1834 mddb_lb_t *lbp,
1835 mddb_rb_t *nm,
1836 pnm_rec_t **pnm,
1837 mdname_t *rsp,
1838 int fd,
1839 md_timeval32_t *lastaccess,
1840 md_error_t *ep
1841 )
1842 {
1843 int rval = 0;
1844 /* list of all metadevices in diskset */
1845 md_im_rec_t *mdimp = NULL;
1846 md_im_rec_t *tmp_mdrec, *rm_mdrec;
1847
1848 /* Read in metadevice records and add entries to mdimp list. */
1849 rval = read_all_mdrecords(&mdimp, mb, lbp, nm, rsp, fd, lastaccess,
1850 ep);
1851 if (rval < 0)
1852 goto out;
1853
1854 /* Adding a fake record to the head of the list of all metadevices. */
1855 if (mdimp != NULL) {
1856 tmp_mdrec = Zalloc(sizeof (md_im_rec_t));
1857 tmp_mdrec->prev = NULL;
1858 mdimp->prev = tmp_mdrec;
1859 tmp_mdrec->next = mdimp;
1860 mdimp = tmp_mdrec;
1861 }
1862
1863 /* Calling functions to process all metadevices on mdimp list */
1864 process_toplevel_devices(&mdimp, *pnm, MDDB_F_SOFTPART);
1865 process_toplevel_devices(&mdimp, *pnm, MDDB_F_TRANS_MASTER);
1866 process_toplevel_devices(&mdimp, *pnm, MDDB_F_MIRROR);
1867 process_toplevel_devices(&mdimp, *pnm, MDDB_F_RAID);
1868 process_toplevel_devices(&mdimp, *pnm, MDDB_F_STRIPE);
1869 process_toplevel_devices(&mdimp, *pnm, MDDB_F_HOTSPARE_POOL);
1870 (void) printf("\n");
1871
1872 out:
1873 /*
1874 * If mdreclist is not null, then this will walk through all
1875 * elements and free them.
1876 */
1877 tmp_mdrec = mdimp;
1878 while (tmp_mdrec != NULL) {
1879 rm_mdrec = tmp_mdrec;
1880 tmp_mdrec = tmp_mdrec->next;
1881 if (rm_mdrec->record != NULL)
1882 Free(rm_mdrec->record);
1883 if (rm_mdrec->n_name != NULL)
1884 Free(rm_mdrec->n_name);
1885 Free(rm_mdrec);
1886 }
1887
1888 free_pnm_rec_list(pnm);
1889 return (rval);
1890 }