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 * 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 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 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 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 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 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 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 * 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 * 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 * 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 }