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