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