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