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