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