diff options
author | mw145384 <none@none> | 2005-10-21 13:01:21 -0700 |
---|---|---|
committer | mw145384 <none@none> | 2005-10-21 13:01:21 -0700 |
commit | 4745263a792e84bbd9e36b3ceb07d1275762cf9b (patch) | |
tree | ca16981779526d27075b6038cb54dc410d36e10b /usr/src | |
parent | aae21359c9c25c5100c4853afd7334521ede3276 (diff) | |
download | illumos-gate-4745263a792e84bbd9e36b3ceb07d1275762cf9b.tar.gz |
6214917 metaimport -r should display metastat info for candidate disksets
6335648 unpacked hot_spare_t structure causes problems with output on AMD64
--HG--
rename : usr/src/uts/common/io/lvm/md/md_convert.c => usr/src/common/lvm/md_convert.c
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/cmd/lvm/util/metaimport.c | 231 | ||||
-rw-r--r-- | usr/src/cmd/lvm/util/metastat.c | 119 | ||||
-rw-r--r-- | usr/src/common/lvm/md_convert.c (renamed from usr/src/uts/common/io/lvm/md/md_convert.c) | 73 | ||||
-rw-r--r-- | usr/src/common/lvm/md_revchk.c | 62 | ||||
-rw-r--r-- | usr/src/head/meta.h | 46 | ||||
-rw-r--r-- | usr/src/lib/lvm/libmeta/Makefile.com | 5 | ||||
-rw-r--r-- | usr/src/lib/lvm/libmeta/common/meta_import.c | 476 | ||||
-rw-r--r-- | usr/src/lib/lvm/libmeta/common/meta_statconcise.c | 1867 | ||||
-rw-r--r-- | usr/src/lib/lvm/libmeta/spec/meta.spec | 18 | ||||
-rw-r--r-- | usr/src/uts/common/Makefile.files | 6 | ||||
-rw-r--r-- | usr/src/uts/common/io/lvm/md/md_mddb.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/io/lvm/md/md_subr.c | 61 | ||||
-rw-r--r-- | usr/src/uts/common/sys/lvm/md_hotspares.h | 8 | ||||
-rw-r--r-- | usr/src/uts/common/sys/lvm/mdvar.h | 5 | ||||
-rw-r--r-- | usr/src/uts/intel/md/Makefile | 6 | ||||
-rw-r--r-- | usr/src/uts/sparc/md/Makefile | 4 |
16 files changed, 2540 insertions, 459 deletions
diff --git a/usr/src/cmd/lvm/util/metaimport.c b/usr/src/cmd/lvm/util/metaimport.c index 37083e7cbd..0ec9adfeb1 100644 --- a/usr/src/cmd/lvm/util/metaimport.c +++ b/usr/src/cmd/lvm/util/metaimport.c @@ -180,206 +180,6 @@ report_overlap_recommendation() Free(mbp); } -static void -report_standard(md_im_set_desc_t *s, int do_cmd, int overlap) -{ - md_im_drive_info_t *d; - md_im_replica_info_t *r; - md_im_drive_info_t *good_disk = NULL; - int i; - md_timeval32_t firstdisktime; - - for (i = 0; s != NULL; s = s->mis_next, i++) { - int time_conflict = 0; - - /* Choose the best drive to use for the import command */ - for (good_disk = NULL, d = s->mis_drives; - d != NULL; d = d->mid_next) { - if (good_disk == NULL) { - for (r = d->mid_replicas; - r != NULL; - r = r->mir_next) { - if (r->mir_flags & MDDB_F_ACTIVE) { - good_disk = d; - break; - } - } - } - } - - /* - * Make the distinction between a regular diskset and - * a replicated diskset. - */ - if (s->mis_flags & MD_IM_SET_REPLICATED) { - (void) fprintf(stdout, "%s :\n", - gettext("Replicated diskset found containing disks")); - } else { - (void) fprintf(stdout, "%s :\n", - gettext("Regular diskset found containing disks")); - } - - - /* - * Save the set creation time from the first disk in the - * diskset and compare the set creation time on all other - * disks in the set to that. If they are the same, the - * disk really belongs here. If they are different the - * disk probably belongs to a different set and we'll - * need to print out a warning. - */ - firstdisktime = s->mis_drives->mid_setcreatetimestamp; - for (d = s->mis_drives; d != NULL; d = d->mid_next) { - if ((firstdisktime.tv_sec == - d->mid_setcreatetimestamp.tv_sec) && - (firstdisktime.tv_usec == - d->mid_setcreatetimestamp.tv_usec)) { - (void) fprintf(stdout, " %s\n", - d->mid_dnp->cname); - } else { - (void) fprintf(stdout, " %s *\n", - d->mid_dnp->cname); - time_conflict = 1; - } - } - - if (time_conflict) { - fprintf(stdout, "* WARNING: This disk has been reused " - "in another set.\n Import may corrupt data in the " - "disk set.\n"); - } - - if (overlap) { - (void) fprintf(stdout, "%s: %s\n", - gettext("Diskset creation time"), - meta_print_time(&s->mis_drives->mid_replicas-> - mir_timestamp)); - } - - /* - * when do_cmd is true, we are not actually importing - * a disk set, but want to print out extra information - */ - if (do_cmd) { - /* - * TRANSLATION_NOTE - * - * The translation of the phrase "For more information - * about this set" will be followed by a ":" and a - * suggested command (untranslatable) that the user - * may use to request additional information. - */ - (void) fprintf(stdout, "%s:\n %s -r -v %s\n", - gettext("For more information about this set"), - myname, good_disk->mid_dnp->cname); - - /* - * TRANSLATION_NOTE - * - * The translation of the phrase "To import this set" - * will be followed by a ":" and a suggested command - * (untranslatable) that the user may use to import - * the specified diskset. - */ - (void) fprintf(stdout, "%s:\n %s -s <newsetname> %s\n", - gettext("To import this set"), myname, - good_disk->mid_dnp->cname); - } - - (void) fprintf(stdout, "\n"); - } - - if (overlap) { - report_overlap_recommendation(); - } -} - -static void -report_verbose(md_im_set_desc_t *s, int do_cmd, int overlap) -{ - md_im_drive_info_t *d; - md_im_replica_info_t *r; - md_im_drive_info_t *good_disk; - static const char fmt1[] = "%-*.*s %12.12s %12.12s %s\n"; - static const char fmt2[] = "%-*.*s %12d %12d "; - int dlen = 0; - int f; - - for (; s != NULL; s = s->mis_next) { - - /* - * Run through the drives in this set to find the one with the - * longest common name and the one we want to consider "best" - */ - for (d = s->mis_drives, good_disk = NULL; - d != NULL; d = d->mid_next) { - dlen = max(dlen, strlen(d->mid_dnp->cname)); - for (r = d->mid_replicas; r != NULL; r = r->mir_next) { - if ((good_disk == NULL) && - (r->mir_flags & MDDB_F_ACTIVE)) { - good_disk = d; - break; - } - } - } - - if (do_cmd) { - (void) fprintf(stdout, "%s: %s -s <newsetname> %s\n", - gettext("To import this set"), myname, - good_disk->mid_dnp->cname); - } - - (void) fprintf(stdout, "%s: %s\n", gettext("Last update"), - meta_print_time(&good_disk->mid_replicas->mir_timestamp)); - - - /* Make sure the length will hold the column heading */ - dlen = max(dlen, strlen(gettext("Device"))); - - (void) fprintf(stdout, fmt1, dlen, dlen, gettext("Device"), - gettext("offset"), gettext("length"), - gettext("replica flags")); - - for (d = s->mis_drives; d != NULL; d = d->mid_next) { - - if (d->mid_replicas != NULL) { - for (r = d->mid_replicas; - r != NULL; - r = r->mir_next) { - (void) fprintf(stdout, fmt2, dlen, dlen, - (r == d->mid_replicas) ? - d->mid_dnp->cname : "", - r->mir_offset, r->mir_length); - - for (f = 0; f < MDDB_FLAGS_LEN; f++) { - (void) putchar( - (r->mir_flags & (1 << f)) ? - MDDB_FLAGS_STRING[f] : ' '); - } - - (void) fprintf(stdout, "\n"); - } - } else { - (void) fprintf(stdout, fmt1, - dlen, dlen, d->mid_dnp->cname, - gettext("no replicas"), "", ""); - } - } - - if (overlap) { - (void) fprintf(stdout, "%s: %s\n", - gettext("Diskset creation time"), - meta_print_time(&s->mis_drives->mid_replicas-> - mir_timestamp)); - } - - (void) fprintf(stdout, "\n"); - } - - if (overlap) { - report_overlap_recommendation(); - } -} int main(int argc, char *argv[]) @@ -390,7 +190,6 @@ main(int argc, char *argv[]) mdsetname_t *sp = NULL; char *setname_new = NULL; int report_only = 0; - int verbose = 0; int version = 0; bool_t dry_run = 0; md_im_names_t cnames = { 0, NULL }; @@ -408,6 +207,8 @@ main(int argc, char *argv[]) int force = 0; int overlap = 0; int partial = 0; + uint_t imp_flags = 0; + int set_count = 0; /* * Get the locale set up before calling any other routines @@ -458,6 +259,7 @@ main(int argc, char *argv[]) case 'r': report_only = 1; + imp_flags |= META_IMP_REPORT; break; case 's': @@ -465,7 +267,7 @@ main(int argc, char *argv[]) break; case 'v': - verbose = 1; + imp_flags |= META_IMP_VERBOSE; break; case 'V': @@ -614,7 +416,13 @@ main(int argc, char *argv[]) goto skipdisk; } - hasreplica = meta_get_set_info(dp, mispp, 0, ep); + /* + * In addition to updating the misp list, either verbose or + * standard output will be generated. + * + */ + hasreplica = meta_get_and_report_set_info(dp, mispp, 0, + imp_flags, &set_count, ep); /* * If current disk is part of a partial diskset, @@ -739,7 +547,6 @@ skipdisk: if (misp->mis_next != NULL) { have_multiple_sets = 1; } - /* * Generate the appropriate (verbose or not) report for all sets * detected. If we're planning on importing later, only include the @@ -753,7 +560,18 @@ skipdisk: * check for the overlapping */ if (have_multiple_sets) { + /* Printing out how many candidate disksets we found. */ + if (imp_flags & META_IMP_REPORT) { + (void) printf("%s: %i\n\n", + gettext("Number of disksets eligible for import"), + set_count); + } + overlap = set_disk_overlap(misp); + if (overlap) { + report_overlap_recommendation(); + } + if (!report_only) { md_eprintf("%s\n\n", gettext("multiple unconfigured " "sets detected.\nRerun the command with the " @@ -761,11 +579,6 @@ skipdisk: } } - if (verbose) { - report_verbose(misp, (report_only || have_multiple_sets), overlap); - } else { - report_standard(misp, (report_only || have_multiple_sets), overlap); - } /* * If it's a report-only request, we're done. If it's an import diff --git a/usr/src/cmd/lvm/util/metastat.c b/usr/src/cmd/lvm/util/metastat.c index c8db40b3fe..7904fa3eab 100644 --- a/usr/src/cmd/lvm/util/metastat.c +++ b/usr/src/cmd/lvm/util/metastat.c @@ -75,22 +75,17 @@ static void print_concise_stripe(int indent, mdsetname_t *sp, static void print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part); static void print_concise_trans(int indent, mdsetname_t *sp, md_trans_t *trans); -static void print_concise_entry(int indent, char *name, diskaddr_t size, - char mtype); static void free_names(mdnamelist_t **nlp); static char *get_sm_state(md_mirror_t *mirror, int i, md_status_t mirror_status, uint_t tstate); static char *get_raid_col_state(md_raidcol_t *colp, uint_t tstate); static char *get_stripe_state(md_comp_t *mdcp, uint_t tstate); static char *get_hs_state(md_hs_t *hsp); -static char *strip_blanks(char *s); static struct sp_base_list *sp_add_done(md_sp_t *part, struct sp_base_list *lp); static int sp_done(md_sp_t *part, struct sp_base_list *lp); static int sp_match(md_sp_t *part, struct sp_base_list *lp); static void sp_free_list(struct sp_base_list *lp); -#define INDENT 4 -#define NAMEWIDTH 16 /* * print named hotspare pool or metadevice @@ -1221,7 +1216,7 @@ print_concise_diskset(mdsetname_t *sp) /* * print the common metadevice hierarchy under these soft parts */ - print_concise_md(INDENT, sp, soft_part->compnamep); + print_concise_md(META_INDENT, sp, soft_part->compnamep); } free_names(&nl); @@ -1350,7 +1345,7 @@ print_concise_mirror(int indent, mdsetname_t *sp, md_mirror_t *mirror) (void) printf("\n"); - indent += INDENT; + indent += META_INDENT; for (i = 0; i < NMIRROR; i++) { if (mirror->submirrors[i].submirnamep == NULL) continue; @@ -1414,7 +1409,7 @@ print_concise_raid(int indent, mdsetname_t *sp, md_raid_t *raid) (void) printf("\n"); - indent += INDENT; + indent += META_INDENT; for (i = 0; i < raid->cols.cols_len; i++) { print_concise_md(indent, sp, raid->cols.cols_val[i].colnamep); } @@ -1485,7 +1480,7 @@ print_concise_stripe(int indent, mdsetname_t *sp, md_stripe_t *stripe) (void) printf("\n"); - indent += INDENT; + indent += META_INDENT; for (i = 0; i < stripe->rows.rows_len; i++) { md_row_t *rowp; int j; @@ -1513,7 +1508,7 @@ print_concise_sp(int indent, mdsetname_t *sp, md_sp_t *part) (void) printf(" %s\n", part->compnamep->cname); - print_concise_md(indent + INDENT, sp, part->compnamep); + print_concise_md(indent + META_INDENT, sp, part->compnamep); } /* @@ -1536,7 +1531,7 @@ print_concise_trans(int indent, mdsetname_t *sp, md_trans_t *trans) (void) printf("\n"); - indent += INDENT; + indent += META_INDENT; print_concise_md(indent, sp, trans->masternamep); @@ -1595,37 +1590,6 @@ print_concise_md(int indent, mdsetname_t *sp, mdname_t *np) } /* - * Print properly indented metadevice name, type and size for concise output. - */ -static void -print_concise_entry(int indent, char *name, diskaddr_t size, char mtype) -{ - int i; - int width = NAMEWIDTH; /* minumum field width for name */ - char in[MAXPATHLEN]; - char *sz; - - in[0] = 0; - for (i = 0; i < indent; i++) - (void) strlcat(in, " ", sizeof (in)); - - /* set up minimum field width. negative for left justified */ - width -= indent; - if (width < 0) - width = 0; /* overflowed; no minimum field needed */ - else - width = 0 - width; /* make it negative for left justification */ - - if (size == 0) { - sz = "-"; - } else { - sz = strip_blanks(meta_number_to_string(size, DEV_BSIZE)); - } - - (void) printf("%s%*s %c %6s", in, width, name, mtype, sz); -} - -/* * Given a name get the unit for use in concise output. We use the *_common * routines in libmeta which allow us to specify the "fast" flag, thereby * avoiding the DKIOCGGEOM ioctl that normally happens. @@ -1739,27 +1703,7 @@ get_raid_col_state(md_raidcol_t *colp, uint_t tstate) if (tstate != 0) return (gettext("unavail")); - switch (colp->state) { - case RCS_INIT: - return (gettext("initializing")); - - case RCS_OKAY: - return (NULL); - - case RCS_INIT_ERRED: - /*FALLTHROUGH*/ - case RCS_ERRED: - return (gettext("maint")); - - case RCS_LAST_ERRED: - return (gettext("last-erred")); - - case RCS_RESYNC: - return (gettext("resyncing")); - - default: - return (gettext("unknown")); - } + return (meta_get_raid_col_state(colp->state)); } /* @@ -1773,18 +1717,7 @@ get_stripe_state(md_comp_t *mdcp, uint_t tstate) if (tstate != 0) return ("unavail"); - switch (state) { - case CS_OKAY: - return (NULL); - case CS_ERRED: - return (gettext("maint")); - case CS_LAST_ERRED: - return (gettext("last-erred")); - case CS_RESYNC: - return (gettext("resyncing")); - default: - return (gettext("invalid")); - } + return (meta_get_stripe_state(state)); } /* @@ -1795,45 +1728,11 @@ get_hs_state(md_hs_t *hsp) { hotspare_states_t state = hsp->state; - switch (state) { - case HSS_AVAILABLE: - return (NULL); - case HSS_RESERVED: - return (gettext("in-use")); - case HSS_BROKEN: - return (gettext("broken")); - case HSS_UNUSED: - default: - return (gettext("invalid")); - } + return (meta_get_hs_state(state)); } /* - * Strip blanks from string. Used for size field in concise output. - */ -static char * -strip_blanks(char *s) -{ - char *p; - - for (p = s; *p; ) { - if (*p == ' ') { - char *t; - - for (t = p; *t; t++) { - *t = *(t + 1); - } - - } else { - p++; - } - } - - return (s); -} - -/* * Keep track of printed soft partitions for concise output. */ static struct sp_base_list * diff --git a/usr/src/uts/common/io/lvm/md/md_convert.c b/usr/src/common/lvm/md_convert.c index cc58be09a1..bb8912b3b9 100644 --- a/usr/src/uts/common/io/lvm/md/md_convert.c +++ b/usr/src/common/lvm/md_convert.c @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -59,17 +59,70 @@ #include <sys/sysmacros.h> #include <sys/types.h> #include <sys/cmn_err.h> - #include <sys/lvm/mdvar.h> +#ifdef _KERNEL +#include <sys/lvm/md_basic.h> +#else /* !_KERNEL */ +#include <meta_basic.h> +#endif /* _KERNEL */ +#include <sys/lvm/md_convert.h> -#include <sys/lvm/md_convert.h> +/* + * SVM private devt expansion routine + * INPUT: dev a 64 bit container holding either a 32 bit or a 64 bit device + * OUTPUT: always an expanded 64 bit device, even if we are running in a + * 32 bit Kernel. + */ +md_dev64_t +md_expldev(md_dev64_t dev) +{ + minor_t minor; + major_t major = (major_t)(dev >> NBITSMINOR64) & MAXMAJ64; + + /* Here we were given a 64bit dev, return unchanged */ + if (major != (major_t)0) + return (dev); + /* otherwise we were given a 32 bit dev */ + major = (major_t)dev >> NBITSMINOR32 & MAXMAJ32; + minor = (minor_t)dev & MAXMIN32; + return (((md_dev64_t)major << NBITSMINOR64) | minor); +} + +/* + * SVM private devt compact routine + * INPUT: dev a 64 bit container holding either a 32 bit or a 64 bit device + * OUTPUT: always a compacted 32 bit device, even if we are running in a + * 64 bit Kernel. + */ +dev32_t +md_cmpldev(md_dev64_t dev) +{ + minor_t minor; + major_t major = (major_t)(dev >> NBITSMINOR64) & MAXMAJ64; + + /* Here we were given a 32bit dev, return unchanged */ + if (major == 0) { + return ((dev32_t)dev); + } + /* otherwise we were given a 64 bit dev */ + minor = (minor_t)dev & MAXMIN32; + return (((dev32_t)major << NBITSMINOR32) | minor); +} + /* * given a small stripe unit, compute the size of an appropriate * big stripe unit. * if first_comp_only is set just return the offset of the first component * in the new big unit. + * + * The function: + * usr/src/lib/lvm/libmeta/common/meta_statconcise.c:get_stripe_req_size() + * contains code derived from this function and thus if any changes are made to + * this function get_stripe_req_size() should be evaluated to determine whether + * or not code changes will also be necessary there. + * */ size_t get_big_stripe_req_size(ms_unit32_od_t *un, int first_comp_only) @@ -152,7 +205,9 @@ get_small_stripe_req_size(ms_unit_t *un, int first_comp_only) void stripe_convert(caddr_t small, caddr_t big, int direction) { + /*LINTED*/ ms_unit32_od_t *small_un = (ms_unit32_od_t *)small; + /*LINTED*/ ms_unit_t *big_un = (ms_unit_t *)big; struct ms_row32_od *small_mdr; @@ -246,7 +301,9 @@ stripe_convert(caddr_t small, caddr_t big, int direction) void mirror_convert(caddr_t small, caddr_t big, int direction) { + /*LINTED*/ mm_unit32_od_t *small_un = (mm_unit32_od_t *)small; + /*LINTED*/ mm_unit_t *big_un = (mm_unit_t *)big; int i; @@ -333,7 +390,9 @@ void raid_convert(caddr_t small, caddr_t big, int direction) { + /*LINTED*/ mr_unit32_od_t *small_un = (mr_unit32_od_t *)small; + /*LINTED*/ mr_unit_t *big_un = (mr_unit_t *)big; int i; @@ -387,7 +446,9 @@ void softpart_convert(caddr_t small, caddr_t big, int direction) { + /*LINTED*/ mp_unit32_od_t *small_un = (mp_unit32_od_t *)small; + /*LINTED*/ mp_unit_t *big_un = (mp_unit_t *)big; if (direction == BIG_2_SMALL) { @@ -426,7 +487,9 @@ softpart_convert(caddr_t small, caddr_t big, int direction) void trans_master_convert(caddr_t smallp, caddr_t bigp, int direction) { + /*LINTED*/ mt_unit32_od_t *small = (mt_unit32_od_t *)smallp; + /*LINTED*/ mt_unit_t *big = (mt_unit_t *)bigp; if (direction == SMALL_2_BIG) { @@ -509,7 +572,9 @@ trans_master_convert(caddr_t smallp, caddr_t bigp, int direction) void trans_log_convert(caddr_t smallp, caddr_t bigp, int direction) { + /*LINTED*/ ml_unit32_od_t *small = (ml_unit32_od_t *)smallp; + /*LINTED*/ ml_unit_t *big = (ml_unit_t *)bigp; if (direction == SMALL_2_BIG) { @@ -589,7 +654,9 @@ void hs_convert(caddr_t small, caddr_t big, int direction) { + /*LINTED*/ hot_spare32_od_t *small_un = (hot_spare32_od_t *)small; + /*LINTED*/ hot_spare_t *big_un = (hot_spare_t *)big; if (direction == BIG_2_SMALL) { diff --git a/usr/src/common/lvm/md_revchk.c b/usr/src/common/lvm/md_revchk.c new file mode 100644 index 0000000000..63af20c83a --- /dev/null +++ b/usr/src/common/lvm/md_revchk.c @@ -0,0 +1,62 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +/* + * Need to include md_mddb.h for the MDDB_REV_MAJOR and MDDB_REV_MINOR + * definitions. The other files included are required for md_mddb.h. + */ +#ifdef _KERNEL +#include <sys/lvm/md_basic.h> +#include <sys/lvm/mdvar.h> +#else /* !_KERNEL */ +#include <meta.h> +#endif /* _KERNEL */ +#include <sys/lvm/md_mddb.h> + + +/* + * revchk() + * Checks the major and minor revision numbers for either an in-core or on-disk + * directory block or record block against the currently defined major and + * minor numbers(MDDB_REV_MAJOR and MDDB_REV_MINOR) to make sure that they are + * compatible with this version of SVM. For example, earlier versions of SVM + * don't understand dummy masterblocks or deviceIDs in disksets. + */ +int +revchk( + uint_t my_rev, + uint_t data +) +{ + if ((MDDB_REV_MAJOR & my_rev) != (MDDB_REV_MAJOR & data)) + return (1); + if ((MDDB_REV_MINOR & my_rev) < (MDDB_REV_MINOR & data)) + return (1); + return (0); +} diff --git a/usr/src/head/meta.h b/usr/src/head/meta.h index 46bb9c0575..af69d7cea4 100644 --- a/usr/src/head/meta.h +++ b/usr/src/head/meta.h @@ -1747,6 +1747,10 @@ extern md_mn_msg_t *copy_msg(md_mn_msg_t *src, md_mn_msg_t *dest); /* meta_import.c */ extern int read_master_block(md_error_t *ep, int fd, void *bp, int bsize); +extern int read_database_block(md_error_t *, int, mddb_mb_t *, int, + void *, int); +extern daddr_t getphysblk(mddb_block_t, mddb_mb_t *); + typedef struct md_im_names { int min_count; char **min_names; @@ -1774,6 +1778,7 @@ typedef struct md_im_drive_info { int mid_o_devid_sz; char mid_minor_name[MDDB_MINOR_NAME_MAX]; md_timeval32_t mid_setcreatetimestamp; + char *mid_devname; md_im_replica_info_t *mid_replicas; struct md_im_drive_info *overlap; /* chain of overlap disks */ } md_im_drive_info_t; @@ -1790,11 +1795,38 @@ typedef struct md_im_set_desc { int mis_active_replicas; } md_im_set_desc_t; +/* + * pnm_rec is used to store the mapping from keys in the NM namespace + * to actual physical devices. The current name of a physical device, used + * by a set that can be imported, can be retrieved by matching the did_key + * (deviceID entry) in the DID_SHR_NM namespace to the min_devid_key in the + * DID_NM namespace(the did_key to the min_key). Then matching the min_key + * in the DID_NM namespace to the n_key in the NM namespace. + * + * n_name is defined to be an array, so that only one malloc is needed for the + * entire datastructure. + */ +typedef struct pnm_rec { + mdkey_t n_key; /* The n_key/min_key value */ + struct pnm_rec *next; + ushort_t n_namlen; + char n_name[1]; /* The name of the physical device */ +} pnm_rec_t; + +/* Indentation value for metaimport output */ +#define META_INDENT 4 + +/* Flags for metaimport reporting */ +#define META_IMP_REPORT 0x0001 +#define META_IMP_VERBOSE 0x0002 + extern int meta_list_disks(md_error_t *, md_im_names_t *); extern mddrivenamelist_t *meta_prune_cnames(md_error_t *, md_im_names_t *, int); -extern int meta_get_set_info(mddrivenamelist_t *, - md_im_set_desc_t **, int, md_error_t *); +extern int meta_get_and_report_set_info( + mddrivenamelist_t *, md_im_set_desc_t **, + int, uint_t, int *, md_error_t *); +extern void free_pnm_rec_list(pnm_rec_t **); extern int meta_imp_set(md_im_set_desc_t *, char *, int, bool_t, md_error_t *); extern int meta_imp_drvused(mdsetname_t *sp, @@ -1871,3 +1903,13 @@ extern int halt_set(mdsetname_t *sp, md_error_t *ep); #endif #endif /* _META_H */ + +/* meta_statconcise.c */ +extern void print_concise_entry(int indent, char *name, + diskaddr_t size, char mtype); +extern char *meta_get_raid_col_state(rcs_state_t); +extern char *meta_get_stripe_state(comp_state_t); +extern char *meta_get_hs_state(hotspare_states_t); +extern int report_metastat_info(mddb_mb_t *, mddb_lb_t *, + mddb_rb_t *, pnm_rec_t **, mdname_t *, int, + md_timeval32_t *, md_error_t *); diff --git a/usr/src/lib/lvm/libmeta/Makefile.com b/usr/src/lib/lvm/libmeta/Makefile.com index ad747e2331..5a2a89cf82 100644 --- a/usr/src/lib/lvm/libmeta/Makefile.com +++ b/usr/src/lib/lvm/libmeta/Makefile.com @@ -20,7 +20,7 @@ # CDDL HEADER END # # -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" @@ -30,7 +30,7 @@ LIBRARY= libmeta.a VERS= .1 COMMON = $(SRC)/common/lvm -CMN_OBJS = md_crc.o +CMN_OBJS = md_crc.o md_convert.o md_revchk.o DERIVED_OBJS = \ mdiox_xdr.o \ @@ -98,6 +98,7 @@ LOCAL_OBJS= \ meta_setup.o \ meta_smf.o \ meta_stat.o \ + meta_statconcise.o \ meta_sp.o \ meta_stripe.o \ meta_systemfile.o \ diff --git a/usr/src/lib/lvm/libmeta/common/meta_import.c b/usr/src/lib/lvm/libmeta/common/meta_import.c index 9da9ca7ebc..650df6fcff 100644 --- a/usr/src/lib/lvm/libmeta/common/meta_import.c +++ b/usr/src/lib/lvm/libmeta/common/meta_import.c @@ -35,10 +35,11 @@ #include "meta_set_prv.h" #include <stdio.h> #include <stdlib.h> -#include <string.h> +#include <strings.h> #include <sys/lvm/md_mddb.h> #include <sys/lvm/md_names.h> #include <sys/lvm/md_crc.h> +#include <sys/lvm/md_convert.h> typedef struct did_list { void *rdid; /* real did if replicated set */ @@ -58,7 +59,7 @@ typedef struct replicated_disk { /* * The current implementation limits the max device id length to 256 bytes. - * Should the max device id length be increased, this define would have to + * Should the max device id length be increased, this definition would have to * be bumped up accordingly */ #define MAX_DEVID_LEN 256 @@ -86,7 +87,7 @@ static int replicated_disk_list_built = 0; * - The kernel routine works on in core master blocks, or mddb_mb_ic_t; this * routine works instead on the mddb_mb_t read directly from the disk */ -static daddr_t +daddr_t getphysblk( mddb_block_t blk, mddb_mb_t *mbp @@ -121,6 +122,7 @@ drive_append( mddrivename_t *dnp, void *devid, void *rdevid, + void *devname, int devid_sz, char *minor_name, md_timeval32_t timestamp, @@ -161,6 +163,9 @@ drive_append( (void) memcpy(midp->mid_devid, devid, devid_sz); } + if (devname) + midp->mid_devname = Strdup(devname); + midp->mid_devid_sz = devid_sz; midp->mid_setcreatetimestamp = timestamp; (void) strlcpy(midp->mid_minor_name, minor_name, MDDB_MINOR_NAME_MAX); @@ -184,14 +189,15 @@ drive_append_wrapper( mddrivename_t *dnp, void *devid, void *rdevid, + void *devname, int devid_sz, char *minor_name, md_timeval32_t timestamp, md_im_replica_info_t *mirp ) { - (void) drive_append(tailpp, dnp, devid, rdevid, devid_sz, minor_name, - timestamp, mirp); + (void) drive_append(tailpp, dnp, devid, rdevid, devname, devid_sz, + minor_name, timestamp, mirp); if ((*tailpp)->mid_next == NULL) return (tailpp); @@ -484,6 +490,7 @@ get_replica_disks( (void) close(fd); midpp = drive_append_wrapper(midpp, dnp, replica_disk->did, replica_disk->rdid, + replica_disk->devname, devid_sz, minor_name, mbp->mb_setcreatetime, NULL); mirpp = &((*midpp)->mid_replicas); @@ -535,20 +542,90 @@ get_replica_disks( } +/* + * append_pnm_rec() + * + * Append pnm_rec_t entry to list of physical devices in the diskset. Entry + * contains a mapping of n_key in NM namespace(or min_key in DID_NM namespace) + * to name of the physical device. This list will be used to ensure that the + * correct names of the physical devices are printed in the metastat output--the + * NM namespace might have stale information about where the physical devices + * were previously located when the diskset was last active. + */ +static void +append_pnm_rec( + pnm_rec_t **pnm, + mdkey_t min_key, + char *n_name +) +{ + pnm_rec_t *tmp_pnm; + char *p; + int len; + + if ((p = strrchr(n_name, '/')) != NULL) + p++; + + /* + * Allocates pnm_rec_t record for the physical + * device. + */ + len = strlen(p) + 1; /* Length of name plus Null term */ + tmp_pnm = Malloc(sizeof (pnm_rec_t) + len); + (void) strncpy(tmp_pnm->n_name, p, len); + tmp_pnm->n_key = min_key; + + /* + * Adds new element to head of pnm_rec_t list. + */ + if (*pnm == NULL) { + tmp_pnm->next = NULL; + *pnm = tmp_pnm; + } else { + tmp_pnm->next = *pnm; + *pnm = tmp_pnm; + } +} + +/* + * free_pnm_rec_list() + * + * Freeing all pnm_rec_t entries on the list of physical devices in the + * diskset. + */ +void +free_pnm_rec_list(pnm_rec_t **pnm) +{ + pnm_rec_t *tmp_pnm, *rm_pnm; + + for (tmp_pnm = *pnm; tmp_pnm != NULL; ) { + rm_pnm = tmp_pnm; + tmp_pnm = tmp_pnm->next; + Free(rm_pnm); + } + + *pnm = NULL; +} + /* - * get_nonreplica_disks() + * get_disks_from_didnamespace() + * This function was origionally called: get_nonreplica_disks() * * Extracts the disks without replicas from the locator name space and adds them * to the supplied list of md_im_drive_info_t. + * If the print verbose option was given then this function will also + * correct the nm namespace so that the n_name is the right ctd name */ static void -get_nonreplica_disks( +get_disks_from_didnamespace( md_im_set_desc_t *misp, + pnm_rec_t **pnm, mddb_rb_t *did_nm, mddb_rb_t *did_shrnm, - md_error_t *ep, - int replicated + uint_t imp_flags, + int replicated, + md_error_t *ep ) { char *search_path = "/dev"; @@ -638,6 +715,14 @@ get_nonreplica_disks( assert(nmlist->devname != NULL); dnp = metadrivename(&sp, metadiskname(nmlist->devname), ep); + /* + * Add drive to pnm_rec_t list of physical devices for + * metastat output. + */ + if (imp_flags & META_IMP_VERBOSE) { + append_pnm_rec(pnm, min->min_key, + nmlist->devname); + } assert(dnp != NULL); /* Is it already on the list? */ @@ -704,10 +789,12 @@ get_nonreplica_disks( /* * If it is replicated diskset, * r_did will be non-NULL and - * devid_sz will be its size + * devid_sz will be its size. + * Passing the devname as NULL because field + * is not currently used for a non-replica disk. */ midpp = drive_append_wrapper(midpp, - dnp, &did->did_devid, r_did, + dnp, &did->did_devid, r_did, NULL, devid_sz, &min->min_name[0], mbp->mb_setcreatetime, NULL); Free(mbp); @@ -734,12 +821,15 @@ set_append( mddb_mb_t *mb, mddb_lb_t *lbp, mddb_rb_t *nm, + pnm_rec_t **pnm, mddb_rb_t *did_nm, mddb_rb_t *did_shrnm, - md_error_t *ep, - int replicated + uint_t imp_flags, + int replicated, + md_error_t *ep ) { + md_im_set_desc_t *misp; set_t setno = mb->mb_setno; @@ -759,47 +849,20 @@ set_append( get_replica_disks(misp, did_listp, mb, lbp, ep, replicated); if (nm != NULL && did_nm != NULL && did_shrnm != NULL) { - get_nonreplica_disks(misp, did_nm, did_shrnm, ep, replicated); + get_disks_from_didnamespace(misp, pnm, did_nm, + did_shrnm, imp_flags, replicated, ep); } /* - * An error in this struct could come from either of the above routines; + * An error in this struct could come from either of + * the above routines; * in both cases, we want to pass it back on up. */ - return (misp); -} - - -/* - * set_append_wrapper() - * - * Constant time append wrapper; the append function will always walk the list, - * this will take a tail argument and use the append function on just the tail - * node, doing the appropriate old-tail-next-pointer bookkeeping. - */ -static md_im_set_desc_t ** -set_append_wrapper( - md_im_set_desc_t **tailpp, - did_list_t *did_listp, - mddb_mb_t *mb, - mddb_lb_t *lbp, - mddb_rb_t *nm, - mddb_rb_t *did_nm, - mddb_rb_t *did_shrnm, - md_error_t *ep, - int replicated -) -{ - (void) set_append(tailpp, did_listp, mb, lbp, nm, did_nm, - did_shrnm, ep, replicated); - - /* it's the first item in the list, return it instead of the next */ - return (((*tailpp)->mis_next == NULL) ? tailpp : &(*tailpp)->mis_next); + return (misp); } - /* * add_disk_names() * @@ -1704,8 +1767,298 @@ check_nm_disks( return (0); } + /* - * meta_get_set_info + * report_metadb_info() + * + * Generates metadb output for the diskset. + * + */ +static void +report_metadb_info( + md_im_set_desc_t *misp, + char *indent +) +{ + md_im_drive_info_t *d; + md_im_replica_info_t *r; + char *unk_str = ""; + int i; + + (void) printf("%s\t%5.5s\t\t%9.9s\t%11.11s\n", indent, gettext("flags"), + gettext("first blk"), gettext("block count")); + + unk_str = gettext("unknown"); + + /* + * Looping through all drives in the diskset to print + * out information about the drive and if the verbose + * option is set print out replica data. + */ + for (d = misp->mis_drives; d != NULL; d = d->mid_next) { + + if (d->mid_replicas != NULL) { + for (r = d->mid_replicas; r != NULL; + r = r->mir_next) { + (void) printf("%s", indent); + for (i = 0; i < MDDB_FLAGS_LEN; i++) { + if (r->mir_flags & (1 << i)) { + (void) putchar( + MDDB_FLAGS_STRING[i]); + } else { + (void) putchar(' '); + } + } + if ((r->mir_offset == -1) && (r->mir_length + == -1)) { + (void) printf("%7.7s\t\t%7.7s\t", + unk_str, unk_str); + } else if (r->mir_length == -1) { + (void) printf("%i\t\t%7.7s\t", + r->mir_offset, unk_str); + } else { + (void) printf("%i\t\t%i\t", + r->mir_offset, r->mir_length); + } + (void) printf("\t%s\n", + d->mid_devname); + } + } + } + (void) printf("\n"); +} + + +/* + * report_set_info() + * + * Returns: + * < 0 for failure + * 0 for success + * + */ +static int +report_set_info( + md_im_set_desc_t *misp, + mddb_mb_t *mb, + mddb_lb_t *lbp, + mddb_rb_t *nm, + pnm_rec_t **pnm, + mdname_t *rsp, + int fd, + uint_t imp_flags, + int set_count, + md_error_t *ep +) +{ + int rval = 0; + md_im_drive_info_t *d; + md_im_replica_info_t *r; + md_im_drive_info_t *good_disk = NULL; + int i; + int in = META_INDENT; + char indent[MAXPATHLEN]; + int dlen = 0; + md_timeval32_t firstdisktime; + md_timeval32_t lastaccess; /* stores last modified timestamp */ + int set_contains_time_conflict = 0; + int disk_time_conflict = 0; + + + /* Calculates the correct indentation. */ + indent[0] = 0; + for (i = 0; i < in; i++) + (void) strlcat(indent, " ", sizeof (indent)); + + /* + * This will print before the information for the first diskset + * if the verbose option was set. + */ + if (set_count == 1) { + if (imp_flags & META_IMP_REPORT) { + (void) printf("\n%s:\n\n", + gettext("Disksets eligible for import")); + } + } + + /* + * Make the distinction between a regular diskset and + * a replicated diskset. + */ + if (misp->mis_flags & MD_IM_SET_REPLICATED) { + if (imp_flags & META_IMP_REPORT) { + (void) printf("%i) %s:\n", set_count, gettext( + "Found replicated diskset containing disks")); + } else { + (void) printf("\n%s:\n", gettext( + "Importing replicated diskset containing disks")); + } + } else { + if (imp_flags & META_IMP_REPORT) { + (void) printf("%i) %s:\n", set_count, gettext( + "Found regular diskset containing disks")); + } else { + (void) printf("\n%s:\n", gettext( + "Importing regular diskset containing disks")); + } + } + + + /* + * Save the set creation time for the first disk in the + * diskset. + */ + for (d = misp->mis_drives; d != NULL; d = d->mid_next) { + dlen = max(dlen, strlen(d->mid_dnp->cname)); + if (good_disk == NULL) { + for (r = d->mid_replicas; r != NULL; r = r->mir_next) { + if (r->mir_flags & MDDB_F_ACTIVE) { + good_disk = d; + firstdisktime = + d->mid_setcreatetimestamp; + break; + } + } + } else { + break; + } + } + + + /* + * Compares the set creation time from the first disk in the + * diskset to the diskset creation time on all other + * disks in the diskset. + * If they are different then the disk probably belongs to a + * different diskset so we will print out a warning. + * + * Looping through all drives in the diskset to print + * out information about the drive. + */ + for (d = misp->mis_drives; d != NULL; disk_time_conflict = 0, + d = d->mid_next) { + /* + * Verify that the disk's seconds and micro-seconds fields + * match the fields for the good_disk. + */ + if ((firstdisktime.tv_sec != + d->mid_setcreatetimestamp.tv_sec) || + (firstdisktime.tv_usec != + d->mid_setcreatetimestamp.tv_usec)) { + disk_time_conflict = 1; + set_contains_time_conflict = 1; + } + + /* Printing disk names. */ + if (disk_time_conflict == 1) { + /* print '*' next to conflicting disk */ + (void) printf("%s%-*.*s *\n", indent, + dlen, dlen, d->mid_dnp->cname); + } else { + (void) printf("%s%-*.*s\n", indent, + dlen, dlen, d->mid_dnp->cname); + } + } + (void) printf("\n"); + + /* + * This note explains the "*" that appears next to the + * disks with metadbs' whose lb_inittime timestamp does not + * match the rest of the diskset. + */ + if (set_contains_time_conflict) { + (void) printf("%s%s\n%s%s\n\n", indent, + gettext("* WARNING: This disk has been reused in " + "another diskset."), indent, gettext("Import may corrupt " + "data in the diskset.")); + } + + + /* + * If the verbose flag was given on the command line, + * we will print out the metastat -c information , the + * creation time, and last modified time for the diskset. + */ + if (imp_flags & META_IMP_VERBOSE) { + (void) printf("%s%s\n", indent, + gettext("Metadatabase information:")); + report_metadb_info(misp, indent); + + /* + * Printing creation time and last modified time. + * Last modified: uses the global variable "lastaccess", + * which is set to the last updated timestamp from all of + * the database blocks(db_timestamp) or record blocks + * (rb_timestamp). + * Creation time is the locator block init time + * (lb_inittime). + */ + lastaccess = good_disk->mid_replicas->mir_timestamp; + + (void) printf("%s%s\n", indent, + gettext("Metadevice information:")); + rval = report_metastat_info(mb, lbp, nm, pnm, rsp, fd, + &lastaccess, ep); + if (rval < 0) { + return (rval); + } + + (void) printf("%s%s:\t%s\n", indent, + gettext("Creation time"), + meta_print_time(&good_disk->mid_replicas->mir_timestamp)); + (void) printf("%s%s:\t%s\n", indent, + gettext("Last modified time"), + meta_print_time(&lastaccess)); + } else { + /* + * Even if the verbose option is not set, we will print the + * creation time for the diskset. + */ + (void) printf("%s%s:\t%s\n", indent, gettext("Creation time"), + meta_print_time(&good_disk->mid_replicas->mir_timestamp)); + } + + + /* + * If the diskset is not actually being imported, then we + * print out extra information about how to import it. + * If the verbose flag was not set, then we will also + * print out information about how to obtain verbose output. + */ + if (imp_flags & META_IMP_REPORT) { + /* + * TRANSLATION_NOTE + * + * The translation of the phrase "For more information + * about this set" will be followed by a ":" and a + * suggested command (untranslatable) that the user + * may use to request additional information. + */ + if (!(imp_flags & META_IMP_VERBOSE)) { + (void) printf("%s%s:\n%s %s -r -v %s\n", indent, + gettext("For more information about this diskset"), + indent, myname, good_disk->mid_dnp->cname); + } + /* + * TRANSLATION_NOTE + * + * The translation of the phrase "To import this set" + * will be followed by a ":" and a suggested command + * (untranslatable) that the user may use to import + * the specified diskset. + */ + (void) printf("%s%s:\n%s %s -s <newsetname> %s\n", indent, + gettext("To import this diskset"), indent, myname, + good_disk->mid_dnp->cname); + } + (void) printf("\n\n"); + + return (rval); +} + + +/* + * meta_get_and_report_set_info * * Scans a given drive for set specific information. If the given drive * has a shared metadb, scans the shared metadb for information pertaining @@ -1718,11 +2071,13 @@ check_nm_disks( * ENOTSUP for partial disksets detected */ int -meta_get_set_info( - mddrivenamelist_t *dp, - md_im_set_desc_t **mispp, - int local_mb_ok, - md_error_t *ep +meta_get_and_report_set_info( + mddrivenamelist_t *dp, + md_im_set_desc_t **mispp, + int local_mb_ok, + uint_t imp_flags, + int *set_count, + md_error_t *ep ) { uint_t s; @@ -1752,6 +2107,8 @@ meta_get_set_info( struct devid_min_rec *did_nmp; int extended_namespace = 0; int replicated = 0; + pnm_rec_t *pnm = NULL; /* list of physical devs in set */ + md_im_set_desc_t *misp; dnp = dp->drivenamep; @@ -1893,7 +2250,7 @@ meta_get_set_info( * nm_rec. Extended namespace handling is left for Phase 2. * * What this should really be is a loop, each iteration of - * which reads in a nm_rec and calls the set_append_wrapper(). + * which reads in a nm_rec and calls the set_append(). */ /*LINTED*/ nmp = (struct nm_rec *)(nm + sizeof (mddb_rb_t)); @@ -1944,10 +2301,17 @@ meta_get_set_info( append: /* Finally, we've got what we need to process this replica. */ - mispp = set_append_wrapper(mispp, did_listp, mbp, lbp, + misp = set_append(mispp, did_listp, mbp, lbp, /*LINTED*/ - (mddb_rb_t *)nm, (mddb_rb_t *)did_nm, (mddb_rb_t *)did_shrnm, - ep, replicated); + (mddb_rb_t *)nm, &pnm, (mddb_rb_t *)did_nm, (mddb_rb_t *)did_shrnm, + imp_flags, replicated, ep); + + *set_count += 1; + rval = report_set_info(misp, mbp, lbp, + /*LINTED*/ + (mddb_rb_t *)nm, &pnm, rsp, fd, imp_flags, *set_count, ep); + if (rval < 0) + goto out; /* Return the fact that we found at least one set */ rval = 1; @@ -1965,6 +2329,8 @@ out: Free(did_nm); if (did_shrnm != NULL) Free(did_shrnm); + if (pnm != NULL) + free_pnm_rec_list(&pnm); /* * If we are at the end of the list, we must free up diff --git a/usr/src/lib/lvm/libmeta/common/meta_statconcise.c b/usr/src/lib/lvm/libmeta/common/meta_statconcise.c new file mode 100644 index 0000000000..79c999c106 --- /dev/null +++ b/usr/src/lib/lvm/libmeta/common/meta_statconcise.c @@ -0,0 +1,1867 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <meta.h> +#include <assert.h> +#include <ctype.h> +#include <mdiox.h> +#include <meta.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <sys/lvm/md_mddb.h> +#include <sys/lvm/md_names.h> +#include <sys/lvm/md_crc.h> +#include <sys/lvm/md_convert.h> + + +/* + * Design Notes: + * + * All of the code in this file supports the addition of metastat -c output + * for the verbose option of metaimport. Some of this code is also used by + * the command metastat for concise output(cmd/lvm/util/metastat.c). + * The code is designed to produce the same output as metastat -c does for a + * given diskset--with a couple exceptions. + * The primary differences between the output for the metastat -c command and + * metastat output for metaimport -v are: + * - the set name is not printed next to each metadevice + * - top-level state information is not printed for some metadevices + * - the percent that a disk has completed resyncing is not listed + * in metaimport -v. + * + * + * The general layout of this file is as follows: + * + * - report_metastat_info() + * This is the primary entry point for the functions in this file, with + * the exception of several functions that are also called from + * cmd/io/lvm/util/metastat.c + * report_metastat_info() calls functions to read in all the the + * Directory blocks and Record blocks and then process the information + * needed to print out the metadevice records in the same format as + * metastat -c. + * + * - read_all_mdrecords() + * Reads in all the Directory blocks in the diskset and verifies their + * validity. For each Directly block, it loops through all Directory + * Entries and for each one that contains a metadevice record calls + * read_md_record(). Because the output is designed to imitate the + * output of metastat -c, we ignore metadevice records for + * optimized resync, changelog, and translog. + * + * - read_md_record() + * Reads in a Directory Entry and its associated Record block. The + * revision information for the Record block is checked and it is + * determined whether or not it is a 64bit Record block or a 32bit record + * block. For each valid Record block, it allocates an md_im_rec_t + * structure and calls extract_mduser_data(). + * + * - extract_mduser_data() + * Populates the md_im_rec_t data structure with information about the + * record's associated metadevice. Also, the name of the metadevice is + * either copied from the NM namespace(if it exists there) or is generated + * from the record's un_self_id. + * + * - process_toplevel_devices() + * For a given metadevice type, searchs through the md_im_rec_t **mdimpp, + * list of all metadevices in the set, to find all records of the + * specified type that do not have a parent and puts them on a temp list. + * The temp list is then iterated through and the associated processing + * function is called. + * + * - process_(trans, hotspare, hotspare_pool, soft_part, mirror, stripe, raid) + * These functions are called by using the dfunc field in the mdimpp list. + * Each process function only understands its own type of metadevice. Once + * it processes the metadevice it was called for, it then loops through + * all of the underlying metadevices. After printing the name of the + * underlying metadevice, it puts in on a list to be processed. If the + * underlying device is a physical device, then print_physical_device is + * called. + * Once all information about the original metadevice is processed, it + * loops through the list of underlying metadevices and calls the + * appropriate function to process them. + * + * - process_toplevel_softparts() + * To match the output for metastat -c, all top-level softpartions + * are printed out in groups based on their underlying metadevice--so that + * the underlying metadevice only needs to be processed once. + * + * - meta_get_(sm_state, raid_col_state, stripe_state, hs_state) + * These functions are used to retrieve the metadevice state information. + * They are also used by the metastat concise routines in + * cmd/lvm/util/metastat.c. + * + */ + + +/* + * md_im_rec is a doubly linked list used to store the rb_data for each + * directory entry that corresponds to a metadevice. + * n_key: is set, if there is an associated entry in the NM namespace. + * dfunc: is set to point to the function that processes the particular + * metadevice associated with the record. + * hs_record_id: is only set, if the metadevice is a hotspare. + * un_self_id: is set for all other records. This is also used to generate + * the name of the metadevice if there is no entry for the metadevice in + * the NM namespace--n_key is not set. + */ +typedef struct md_im_rec { + mdkey_t n_key; /* NM namespace key */ + struct md_im_rec *next; + struct md_im_rec *prev; + uint_t md_type; + uint_t has_parent; /* either 0(no parent) or 1 */ + minor_t un_self_id; + mddb_recid_t hs_record_id; /* hotspare recid */ + char *n_name; /* name of metadevice */ + void (*dfunc) (); + ushort_t record_len; + /* pointer to the unit structure for the metadevice, e.g. rb_data[0] */ + void *record; +} md_im_rec_t; + +/* + * md_im_list is used to group toplevel metadevices by type and to group + * the underlying devices for a particular metadevice. + */ +typedef struct md_im_list { + struct md_im_list *next; + struct md_im_rec *mdrec; +} md_im_list_t; + + +/* + * MAXSIZEMDRECNAME is the value that has historically been used to allocate + * space for the metadevice name + */ +#define MAXSIZEMDRECNAME 20 +#define NAMEWIDTH 16 +#define offsetof(s, m) ((size_t)(&(((s *)0)->m))) +#define NOT_PHYSICAL_DEV 0 +#define PHYSICAL_DEV 1 + + +/* + * strip_blacks() + * + * Strip blanks from string. Used for size field in concise output. + */ +static char * +strip_blanks(char *s) +{ + char *p; + + for (p = s; *p; ) { + if (*p == ' ') { + char *t; + for (t = p; *t; t++) { + *t = *(t + 1); + } + } else { + p++; + } + } + + return (s); +} + + +/* + * print_concise_entry() + * + * Print properly indented metadevice name, type and size for concise output. + * This function is also called from: cmd/lvm/util/metastat.c. + */ +void +print_concise_entry(int indent, char *name, diskaddr_t size, char mtype) +{ + int i; + int width = NAMEWIDTH; /* minumum field width for name */ + char in[MAXPATHLEN]; + char *sz; + + in[0] = 0; + for (i = 0; i < indent; i++) + (void) strlcat(in, " ", sizeof (in)); + + /* set up minimum field width. negative for left justified */ + width -= indent; + if (width < 0) + width = 0; /* overflowed; no minimum field needed */ + else + width = 0 - width; /* negative for left justification */ + + if (size == 0) { + sz = "-"; + } else { + sz = strip_blanks(meta_number_to_string(size, DEV_BSIZE)); + } + + (void) printf("%s%*s %c %6s", in, width, name, mtype, sz); +} + + +/* + * free_mdrec_list_entry() + * + * Removing entry from the list of metadevices in the diskset(mdimpp). + * This function will not remove the dummy entry at the head of the + * list, so we don't have to set mdrec equal to NULL. + */ +static void +free_mdrec_list_entry(md_im_rec_t **mdrec) +{ + (*mdrec)->prev->next = (*mdrec)->next; + if ((*mdrec)->next != NULL) { + (*mdrec)->next->prev = (*mdrec)->prev; + } + Free((*mdrec)->record); + Free((*mdrec)->n_name); + Free(*mdrec); +} + + +/* + * ucomponent_append() + * + * Appending entry to the underlying component list. The list + * is used to group all of the underlying devices before + * processing them. + */ +static void +ucomponent_append( + md_im_list_t **ucomp_head, + md_im_list_t **ucomp_tail, + md_im_list_t *ucomp +) +{ + ucomp->next = NULL; + if (*ucomp_head == NULL) { + *ucomp_head = ucomp; + *ucomp_tail = ucomp; + } else { + (*ucomp_tail)->next = ucomp; + *ucomp_tail = (*ucomp_tail)->next; + } +} + + +/* + * free_md_im_list_entries() + * + * Freeing entries on an md_im_list_t. This list is used to group + * underlying components for processing and to group top-level metadevices + * by type. + */ +static void +free_md_im_list_entries(md_im_list_t **list_head) +{ + md_im_list_t *tmp_list_entry = *list_head; + md_im_list_t *rm_list_entry; + + while (tmp_list_entry != NULL) { + rm_list_entry = tmp_list_entry; + tmp_list_entry = tmp_list_entry->next; + Free(rm_list_entry); + } +} + + +/* + * print_physical_device() + * + * If a metadevice has an underlying component that is a physical + * device, then this searches the pnm_rec_t list to match an entry's + * n_key to the key for the underlying component. The ctd name of the + * physical device is printed on the same line as the metadevice. + */ +static void +print_physical_device( + pnm_rec_t *phys_nm, + mdkey_t key +) +{ + pnm_rec_t *tmpphys_nm; + + for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; + tmpphys_nm = tmpphys_nm->next) { + if (tmpphys_nm->n_key == key) { + (void) printf(" %s", tmpphys_nm->n_name); + break; + } + } +} + + +/* + * get_stripe_req_size() + * + * Given a 64bit stripe unit, compute the size of the stripe unit. + * This function is a derivation of: + * common/lvm/md_convert.c:get_big_stripe_req_size() + * and any changes made to either this function or get_big_stripe_req_size() + * should be reviewed to make sure the functionality in both places is correct. + * + * Returns: + * total size of the 64bit stripe + */ +size_t +get_stripe_req_size(ms_unit_t *un) +{ + struct ms_row *mdr; + uint_t row; + uint_t ncomps = 0; + size_t mdsize = 0; + size_t first_comp = 0; + + + /* Compute the offset of the first component */ + first_comp = sizeof (ms_unit_t) + + sizeof (struct ms_row) * (un->un_nrows - 1); + first_comp = roundup(first_comp, sizeof (long long)); + + /* + * Requestor wants to have the total size, add the sizes of + * all components + */ + mdr = &un->un_row[0]; + for (row = 0; (row < un->un_nrows); row++) + ncomps += mdr[row].un_ncomp; + mdsize = first_comp + sizeof (ms_comp_t) * ncomps; + return (mdsize); +} + + +/* + * meta_get_sm_state() + * + * Gets the state for the underlying components(submirrors) of a mirror. + * This function is also called from: cmd/lvm/util/metastat.c. + * + * Returns: + * string for state of the sub-mirror + */ +static char * +meta_get_sm_state( + sm_state_t state +) +{ + /* all is well */ + if (state & SMS_RUNNING) { + return (NULL); + } + + /* resyncing, needs repair */ + if ((state & (SMS_COMP_RESYNC | SMS_ATTACHED_RESYNC | + SMS_OFFLINE_RESYNC))) { + return (gettext("resyncing")); + } + + /* needs repair */ + if (state & (SMS_COMP_ERRED | SMS_ATTACHED | SMS_OFFLINE)) + return (gettext("maint")); + + /* unknown */ + return (gettext("unknown")); +} + + +/* + * meta_get_raid_col_state() + * + * Gets the state for the underlying components(columns) of a raid. + * This function is also called from: cmd/lvm/util/metastat.c. + * + * Returns: + * string for state of the raid column + * + */ +char * +meta_get_raid_col_state( + rcs_state_t state +) +{ + switch (state) { + case RCS_INIT: + return (gettext("initializing")); + case RCS_OKAY: + return (NULL); + case RCS_INIT_ERRED: + /*FALLTHROUGH*/ + case RCS_ERRED: + return (gettext("maint")); + case RCS_LAST_ERRED: + return (gettext("last-erred")); + case RCS_RESYNC: + return (gettext("resyncing")); + default: + return (gettext("unknown")); + } +} + + +/* + * meta_get_stripe_state() + * + * Gets the state for the underlying components of a stripe. + * This function is also called from: cmd/lvm/util/metastat.c. + * + * Returns: + * string for state of the stripe + * + */ +char * +meta_get_stripe_state( + comp_state_t state +) +{ + switch (state) { + case CS_OKAY: + return (NULL); + case CS_ERRED: + return (gettext("maint")); + case CS_LAST_ERRED: + return (gettext("last-erred")); + case CS_RESYNC: + return (gettext("resyncing")); + default: + return (gettext("invalid")); + } +} + + +/* + * meta_get_hs_state() + * + * Gets the state for the underlying components(hotspares) of a hotspare pool. + * This function is also called from: cmd/lvm/util/metastat.c. + * + * Returns: + * string for state of the hotspare + * + */ +char * +meta_get_hs_state( + hotspare_states_t state +) +{ + switch (state) { + case HSS_AVAILABLE: + return (NULL); + case HSS_RESERVED: + return (gettext("in-use")); + case HSS_BROKEN: + return (gettext("broken")); + case HSS_UNUSED: + /* FALLTHROUGH */ + default: + return (gettext("invalid")); + } +} + + +/* + * process_trans() + * + * Prints unit information for a trans metadevice and calls the respective + * functions to process the underlying metadevices. + * + */ +static void +process_trans( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm, + md_im_rec_t *mdrec +) +{ + mt_unit_t *mt; + mdc_unit_t uc; + md_im_rec_t *tmpmdrec; + int underlying_device = PHYSICAL_DEV; + + mt = (mt_unit_t *)mdrec->record; + uc = mt->c; + + /* Printing name, size, and type of metadevice */ + print_concise_entry(indent, mdrec->n_name, + uc.un_total_blocks, 't'); + + /* + * Loops through md_im_rec_t **mdimpp list of all metadevices to find + * record that matches the underlying device. + * Trans devices can only have one underlying device, so once a + * match is found, we are done. + */ + for (tmpmdrec = *mdimpp; tmpmdrec != NULL; + tmpmdrec = tmpmdrec->next) { + if (tmpmdrec->n_key == mt->un_m_key) { + /* Printing name of the underlying metadevice */ + (void) printf(" %s", tmpmdrec->n_name); + underlying_device = NOT_PHYSICAL_DEV; + break; + } + } + + /* + * If a metadevice was not found, then the underlying device must be a + * physical device. Otherwise, call the functions to process the + * underlying devices. + */ + if (underlying_device == PHYSICAL_DEV) { + print_physical_device(phys_nm, mt->un_m_key); + (void) printf("\n"); + } else { + /* process underlying component */ + (void) printf("\n"); + indent += META_INDENT; + tmpmdrec->dfunc(mdimpp, indent, phys_nm, tmpmdrec); + } + + /* + * Removing the md_entry from the list + * of all metadevices + */ + free_mdrec_list_entry(&mdrec); +} + + +/* + * process_hotspare() + * + * Searches though list of physical devices to match hotspare record. + * Prints physical device name and state of a hotspare unit. + * + */ +/*ARGSUSED*/ +static void +process_hotspare( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm, + md_im_rec_t *mdrec +) +{ + hot_spare_t *hs; + pnm_rec_t *tmpphys_nm; + char *state = NULL; + + hs = (hot_spare_t *)mdrec->record; + + /* + * Loops through physical namespace to find the device that matches + * the hotspare entry. + */ + for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; + tmpphys_nm = tmpphys_nm->next) { + if (tmpphys_nm->n_key == + ((hot_spare_t *)hs)->hs_key) { + /* Printing name of hotspare device */ + (void) printf(" %s", tmpphys_nm->n_name); + break; + } + } + + state = meta_get_hs_state(hs->hs_state); + if (state != NULL) + (void) printf(" (%s)", state); + + /* Not removing entry, because it can be processed more than once. */ +} + + +/* + * process_hotspare_pool() + * + * Prints concise unit information for a hotspare pool metadevice and calls a + * function to process each attached hotspare device. + * + */ +static void +process_hotspare_pool( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm, + md_im_rec_t *mdrec +) +{ + hot_spare_pool_ond_t *hsp; + int i; + md_im_rec_t *tmpmdrec; + + hsp = (hot_spare_pool_ond_t *)mdrec->record; + + /* + * Printing name, size, and type of metadevice. Setting size field to + * 0, so that output is the as metastat -c. + */ + print_concise_entry(indent, mdrec->n_name, + 0, 'h'); + + /* Looping through list of attached hotspare devices. */ + for (i = 0; i < hsp->hsp_nhotspares; i++) { + /* Looking for the matching record for the hotspare device. */ + for (tmpmdrec = *mdimpp; tmpmdrec != NULL; + tmpmdrec = tmpmdrec->next) { + if (tmpmdrec->hs_record_id == hsp->hsp_hotspares[i]) { + /* Calling function to print name of hotspare */ + tmpmdrec->dfunc(mdimpp, indent, phys_nm, + tmpmdrec); + } + } + } + (void) printf("\n"); + + /* + * Removing the md_entry from the list + * of all metadevices + */ + free_mdrec_list_entry(&mdrec); +} + + +/* + * process_raid() + * + * Prints concise unit information for a raid metadevice and calls the + * respective functions to process the underlying metadevices. + * + */ +static void +process_raid( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm, + md_im_rec_t *mdrec +) +{ + mr_unit_t *mr; + mr_column_t *mc; + mdc_unit_t uc; + int i; + md_im_rec_t *tmpmdrec; + md_im_rec_t *hstmpmdrec; + md_im_list_t *ucomp_head = NULL; + md_im_list_t *ucomp_tail = NULL; + md_im_list_t *ucomp = NULL; + pnm_rec_t *tmpphys_nm; + int underlying_device; + + mr = (mr_unit_t *)mdrec->record; + uc = mr->c; + + /* Printing name, size, and type of metadevice */ + print_concise_entry(indent, mdrec->n_name, + uc.un_total_blocks, 'r'); + + /* Loops through raid columns to find underlying metadevices */ + for (i = 0, mc = &mr->un_column[0]; i < mr->un_totalcolumncnt; + i++, mc++) { + char *state = NULL; + char *hsname = NULL; + + /* + * Need to assume that underlying device is a physical device, + * unless we find a matching metadevice record. + */ + underlying_device = PHYSICAL_DEV; + + /* + * Loops through list of metadevices to find record that matches + * the underlying device. + */ + for (tmpmdrec = *mdimpp; tmpmdrec != NULL; + tmpmdrec = tmpmdrec->next) { + if (tmpmdrec->n_key == mc->un_orig_key) { + /* check if hotspare device enabled */ + if (mc->un_hs_id != NULL) { + /* + * Find matching metadevice record + * for the hotspare device. + */ + for (hstmpmdrec = *mdimpp; + hstmpmdrec != NULL; + hstmpmdrec = hstmpmdrec->next) { + if (hstmpmdrec->hs_record_id == + mc->un_hs_id) { + /* print name of hs */ + hstmpmdrec->dfunc( + mdimpp, indent, + phys_nm, + hstmpmdrec); + break; + } + } + } + /* print name of underlying metadevice */ + (void) printf(" %s", tmpmdrec->n_name); + underlying_device = NOT_PHYSICAL_DEV; + ucomp = Zalloc(sizeof (md_im_list_t)); + ucomp->mdrec = tmpmdrec; + ucomponent_append(&ucomp_head, &ucomp_tail, + ucomp); + } + } + + if (underlying_device == PHYSICAL_DEV) { + print_physical_device(phys_nm, mc->un_orig_key); + } + state = meta_get_raid_col_state(mc->un_devstate); + + /* + * An underlying hotspare must be a physical device. + * If support is ever added for soft-partitions under + * hotspare pools, then this code should be updated to + * include a search for underlying metadevices. + */ + if (mc->un_hs_id != 0) { + for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; + tmpphys_nm = tmpphys_nm->next) { + if (tmpphys_nm->n_key == mc->un_hs_key) { + hsname = tmpphys_nm->n_name; + break; + } + } + } + + if (state != NULL) { + if (hsname != NULL) + (void) printf(" (%s-%s)", state, + hsname); + else + (void) printf(" (%s)", state); + } else if (hsname != NULL) { + (void) printf(gettext(" (spared-%s)"), hsname); + } + } + (void) printf("\n"); + + /* process underlying components */ + indent += META_INDENT; + for (ucomp = ucomp_head; ucomp != NULL; + ucomp = ucomp->next) { + ucomp->mdrec->dfunc(mdimpp, indent, phys_nm, + ucomp->mdrec); + } + free_md_im_list_entries(&ucomp_head); + + /* + * Removing the md_entry from the list + * of all metadevices + */ + free_mdrec_list_entry(&mdrec); +} + + +/* + * process_mirror() + * + * Prints concise unit information for a mirror metadevice and calls the + * respective functions to process the underlying metadevices. + * + */ +static void +process_mirror( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm, + md_im_rec_t *mdrec +) +{ + mm_unit_t *mm; + mm_submirror_t *sm; + mdc_unit_t uc; + int i; + md_im_rec_t *tmpmdrec; + md_im_list_t *ucomp_head = NULL; + md_im_list_t *ucomp_tail = NULL; + md_im_list_t *ucomp = NULL; + + mm = (mm_unit_t *)mdrec->record; + uc = mm->c; + + /* Printing name, size, and type of metadevice */ + print_concise_entry(indent, mdrec->n_name, + uc.un_total_blocks, 'm'); + + /* Looping through sub-mirrors to find underlying devices */ + for (i = 0, sm = &mm->un_sm[0]; i < mm->un_nsm; i++, sm++) { + char *state = NULL; + + for (tmpmdrec = *mdimpp; tmpmdrec != NULL; + tmpmdrec = tmpmdrec->next) { + if (tmpmdrec->n_key == sm->sm_key) { + (void) printf(" %s", tmpmdrec->n_name); + ucomp = Zalloc(sizeof (md_im_list_t)); + ucomp->mdrec = tmpmdrec; + ucomponent_append(&ucomp_head, &ucomp_tail, + ucomp); + } + } + + /* + * It is not possible to have an underlying physical device + * for a submirror, so there is no need to search the phys_nm + * list. + */ + + /* Printing the state for the submirror */ + state = meta_get_sm_state(sm->sm_state); + if (state != NULL) { + (void) printf(" (%s)", state); + } + } + (void) printf("\n"); + + /* process underlying components */ + indent += META_INDENT; + for (ucomp = ucomp_head; ucomp != NULL; + ucomp = ucomp->next) { + ucomp->mdrec->dfunc(mdimpp, indent, phys_nm, + ucomp->mdrec); + } + free_md_im_list_entries(&ucomp_head); + + /* + * Removing the md_entry from the list + * of all metadevices + */ + free_mdrec_list_entry(&mdrec); +} + + +/* + * process_stripe() + * + * Prints concise unit information for a stripe metadevice and calls the + * respective functions to process the underlying metadevices. + * + */ +static void +process_stripe( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm, + md_im_rec_t *mdrec +) +{ + ms_unit_t *ms; + mdc_unit_t uc; + md_im_rec_t *tmpmdrec; + md_im_list_t *ucomp_head = NULL; + md_im_list_t *ucomp_tail = NULL; + md_im_list_t *ucomp = NULL; + pnm_rec_t *tmpphys_nm; + int underlying_device; + uint_t row; + + ms = (ms_unit_t *)mdrec->record; + uc = ms->c; + + /* Printing name, size, and type of metadevice */ + print_concise_entry(indent, mdrec->n_name, + uc.un_total_blocks, 's'); + + /* Looping through stripe rows */ + for (row = 0; (row < ms->un_nrows); ++row) { + struct ms_row *mdr = &ms->un_row[row]; + ms_comp_t *mdcomp = (void *)&((char *)ms) + [ms->un_ocomp]; + uint_t comp, c; + + /* + * Looping through the components in each row to find the + * underlying devices. + */ + for (comp = 0, c = mdr->un_icomp; (comp < mdr->un_ncomp); + ++comp, ++c) { + char *state = NULL; + char *hsname = NULL; + ms_comp_t *mdc = &mdcomp[c]; + md_m_shared_t *mdm = &mdc->un_mirror; + + /* + * Need to assume that underlying device is a + * physical device, unless we find a matching + * metadevice record. + */ + underlying_device = PHYSICAL_DEV; + + for (tmpmdrec = *mdimpp; tmpmdrec != NULL; + tmpmdrec = tmpmdrec->next) { + if (tmpmdrec->n_key == mdc->un_key) { + (void) printf(" %s", tmpmdrec->n_name); + underlying_device = NOT_PHYSICAL_DEV; + ucomp = Zalloc(sizeof (md_im_list_t)); + ucomp->mdrec = tmpmdrec; + ucomponent_append(&ucomp_head, + &ucomp_tail, ucomp); + } + } + /* if an underlying metadevice was not found */ + if (underlying_device == PHYSICAL_DEV) { + print_physical_device(phys_nm, mdc->un_key); + } + state = meta_get_stripe_state(mdm->ms_state); + + /* + * An underlying hotspare must be a physical device. + * If support is ever added for soft-partitions under + * hotspare pools, then this code should be updated to + * include a search for underlying metadevices. + */ + if (mdm->ms_hs_key != 0) { + for (tmpphys_nm = phys_nm; tmpphys_nm != NULL; + tmpphys_nm = tmpphys_nm->next) { + if (tmpphys_nm->n_key == + mdm->ms_hs_key) { + hsname = tmpphys_nm->n_name; + break; + } + } + } + if (state != NULL) { + if (hsname != NULL) { + (void) printf(" (%s-%s)", state, + hsname); + } else { + (void) printf(" (%s)", state); + } + } else if (hsname != NULL) { + (void) printf(gettext(" (spared-%s)"), hsname); + } + } + } + (void) printf("\n"); + + /* Process underlying metadevices */ + indent += META_INDENT; + for (ucomp = ucomp_head; ucomp != NULL; + ucomp = ucomp->next) { + ucomp->mdrec->dfunc(mdimpp, indent, phys_nm, + ucomp->mdrec); + } + free_md_im_list_entries(&ucomp_head); + + /* + * Removing the md_entry from the list + * of all metadevices + */ + free_mdrec_list_entry(&mdrec); +} + + +/* + * process_softpart() + * + * Prints concise unit information for a softpart metadevice and calls the + * respective functions to process the underlying metadevices. + * + */ +static void +process_softpart( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm, + md_im_rec_t *mdrec +) +{ + mp_unit_t *mp; + mdc_unit_t uc; + md_im_rec_t *tmpmdrec; + int underlying_device = PHYSICAL_DEV; + + mp = (mp_unit_t *)mdrec->record; + uc = mp->c; + + /* Printing name, size, and type of metadevice */ + print_concise_entry(indent, mdrec->n_name, + uc.un_total_blocks, 'p'); + + /* + * Loops through md_im_rec_t **mdimpp list of all metadevices to find + * record that matches the underlying device. + * Softpartitions can only have one underlying device, so once a + * match is found, we are done. + */ + for (tmpmdrec = *mdimpp; tmpmdrec != NULL; + tmpmdrec = tmpmdrec->next) { + if (tmpmdrec->n_key == mp->un_key) { + /* Printing name of the underlying metadevice */ + (void) printf(" %s", tmpmdrec->n_name); + underlying_device = NOT_PHYSICAL_DEV; + break; + } + } + + /* This is only executed if an underlying metadevice was not found */ + if (underlying_device == PHYSICAL_DEV) { + print_physical_device(phys_nm, mp->un_key); + (void) printf("\n"); + } else { + /* Process underlying metadevice */ + (void) printf("\n"); + indent += META_INDENT; + tmpmdrec->dfunc(mdimpp, indent, phys_nm, + tmpmdrec); + } + + /* + * Removing the md_entry from the list + * of all metadevices + */ + free_mdrec_list_entry(&mdrec); +} + + +/* + * process_toplevel_softparts() + * + * Toplevel softpartions need to be grouped so that their underlying devices + * can be printed just once. + */ +static void +process_toplevel_softparts( + md_im_rec_t **mdimpp, + int indent, + pnm_rec_t *phys_nm +) +{ + mp_unit_t *mp; + mdc_unit_t uc; + md_im_rec_t *mdrec; + md_im_rec_t *comp_mdrec; /* pntr to underlying component's record */ + md_im_rec_t *tmp_mdrec, *rm_mdrec; + mp_unit_t *tmp_mp; + int underlying_device; + + /* + * Loops through md_im_rec_t **mdimpp list of all metadevices to find + * all softpartions that are toplevel softpartitions(softparts w/out + * a parent). Groups output for these entries so that the function to + * process the underlying metadevice is only called once. + */ + for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) { + + underlying_device = PHYSICAL_DEV; + if ((mdrec->md_type == MDDB_F_SOFTPART) && + (mdrec->has_parent == 0)) { + mp = (mp_unit_t *)mdrec->record; + uc = mp->c; + /* Printing name, size, and type of metadevice */ + print_concise_entry(indent, mdrec->n_name, + uc.un_total_blocks, 'p'); + /* + * Looking for record that matches underlying + * component. + */ + for (comp_mdrec = *mdimpp; comp_mdrec != NULL; + comp_mdrec = comp_mdrec->next) { + if (comp_mdrec->n_key == mp->un_key) { + /* Print name of underlying device */ + (void) printf(" %s", + comp_mdrec->n_name); + underlying_device = NOT_PHYSICAL_DEV; + break; + } + } + if (underlying_device == PHYSICAL_DEV) { + print_physical_device(phys_nm, mp->un_key); + } + (void) printf("\n"); + + /* + * Looking for any other toplevel softpartitions with + * same underlying device. We know that all other + * matching metadevices, that share the same underlying + * metadevice, are also soft-partitions. + */ + for (tmp_mdrec = mdrec->next; tmp_mdrec != NULL; ) { + tmp_mp = (mp_unit_t *)tmp_mdrec->record; + if ((tmp_mdrec->has_parent == 0) && + (tmp_mp->un_key == mp->un_key)) { + uc = tmp_mp->c; + print_concise_entry(indent, + tmp_mdrec->n_name, + uc.un_total_blocks, 'p'); + if (underlying_device == + NOT_PHYSICAL_DEV) { + (void) printf(" %s", + comp_mdrec->n_name); + } else { + print_physical_device( + phys_nm, tmp_mp->un_key); + } + (void) printf("\n"); + /* + * Need to advance so that will not lose + * position after removing processed + * record. + */ + rm_mdrec = tmp_mdrec; + tmp_mdrec = tmp_mdrec->next; + /* + * Removing the md_entry from the list + * of all metadevices. + */ + free_mdrec_list_entry(&rm_mdrec); + } else { + tmp_mdrec = tmp_mdrec->next; + } + } + /* Process the underlying device */ + if (underlying_device == NOT_PHYSICAL_DEV) { + indent += META_INDENT; + comp_mdrec->dfunc(mdimpp, indent, phys_nm, + comp_mdrec); + } + } + } +} + + +/* + * process_toplevel_devices() + * + * Search through list of metadevices for metadevices of md_type that do not + * have a parent. + * + */ +static void +process_toplevel_devices( + md_im_rec_t **mdimpp, + pnm_rec_t *pnm, + uint_t md_type +) +{ + md_im_rec_t *mdrec; + md_im_list_t *mdrec_tl_tail = NULL; + md_im_list_t *mdrec_tl_head = NULL; + md_im_list_t *tmp_tl_list = NULL; + int indent = 0; + + indent += META_INDENT; + + /* + * Need to group soft partitions so that common underlying device + * are only processed once. + */ + if (md_type == MDDB_F_SOFTPART) { + process_toplevel_softparts(mdimpp, indent, pnm); + return; + } + + /* + * Search the list of metadevices to find all metadevices that match + * the type and don't have a parent. Put them on a separate list + * that will be processed. + */ + for (mdrec = *mdimpp; mdrec != NULL; mdrec = mdrec->next) { + if ((mdrec->md_type == md_type)&&(mdrec->has_parent == 0)) { + tmp_tl_list = Zalloc(sizeof (md_im_list_t)); + tmp_tl_list->mdrec = mdrec; + tmp_tl_list->next = NULL; + if (mdrec_tl_tail == NULL) { + mdrec_tl_tail = tmp_tl_list; + mdrec_tl_head = mdrec_tl_tail; + } else { + mdrec_tl_tail->next = tmp_tl_list; + mdrec_tl_tail = mdrec_tl_tail->next; + } + } + + } + + /* + * Loop through list and process all top-level metadevices of a + * given type. + */ + for (tmp_tl_list = mdrec_tl_head; tmp_tl_list != NULL; + tmp_tl_list = tmp_tl_list->next) { + tmp_tl_list->mdrec->dfunc(mdimpp, indent, pnm, + tmp_tl_list->mdrec); + } + + free_md_im_list_entries(&mdrec_tl_head); +} + + +/* + * extract_mduser_data() + * + * Converts or copies the (mddb_rb_t->rb_data) metadevice record to a 64bit + * record. + * Sets the dfunc field to point to the appropriate function to process the + * metadevice. + * Sets the parent field for the metadevice. + * Extracts the name from the NM namespace if it is available, otherwise + * generates it from the metadevice's minor number. + * + * Returns: + * < 0 for failure + * 0 for success + * + */ +static int +extract_mduser_data( + mddb_rb_t *nm, + md_im_rec_t *mdrec, + void *rbp, + int is_32bit_record, + md_error_t *ep +) +{ + mdc_unit_t uc; + hot_spare_t *hs; + hot_spare_pool_ond_t *hsp; + size_t newreqsize; + mddb_rb_t *rbp_nm = nm; + struct nm_rec *nm_record; + struct nm_name *nmname; + char *uname = NULL; + + + /*LINTED*/ + nm_record = (struct nm_rec *)((caddr_t)(&rbp_nm->rb_data)); + + /* + * Setting the un_self_id or the hs_self_id, in the case of hotspare + * records, for each metadevice entry. Also setting has_parent and + * setting dfunc so that it points to the correct function to process + * the record type. + * If the record was stored ondisk in 32bit format, then it is + * converted to the 64bits equivalent 64bit format and the memory + * for the 32bit pointer is freed. + */ + switch (mdrec->md_type) { + case MDDB_F_SOFTPART: + if (is_32bit_record) { + mp_unit32_od_t *small_un; + mp_unit_t *big_un; + + small_un = (mp_unit32_od_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (mp_unit_t) + + ((small_un->un_numexts - 1) * + sizeof (struct mp_ext)); + big_un = (void *)Zalloc(newreqsize); + softpart_convert((caddr_t)small_un, + (caddr_t)big_un, SMALL_2_BIG); + mdrec->record = (void *)big_un; + } else { + mp_unit_t *big_un; + + big_un = (mp_unit_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (mp_unit_t) + + ((big_un->un_numexts - 1) * + sizeof (struct mp_ext)); + mdrec->record = (void *)Zalloc(newreqsize); + bcopy(big_un, mdrec->record, newreqsize); + } + uc = ((mp_unit_t *)mdrec->record)->c; + mdrec->dfunc = &process_softpart; + mdrec->un_self_id = uc.un_self_id; + mdrec->has_parent = MD_HAS_PARENT( + uc.un_parent); + break; + case MDDB_F_STRIPE: + if (is_32bit_record) { + ms_unit32_od_t *small_un; + ms_unit_t *big_un; + + small_un = (ms_unit32_od_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = get_big_stripe_req_size( + small_un, COMPLETE_STRUCTURE); + big_un = (void *)Zalloc(newreqsize); + stripe_convert((caddr_t)small_un, + (caddr_t)big_un, SMALL_2_BIG); + mdrec->record = (void *)big_un; + } else { + ms_unit_t *big_un; + + big_un = (ms_unit_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = get_stripe_req_size(big_un); + mdrec->record = (void *)Zalloc(newreqsize); + bcopy(big_un, mdrec->record, newreqsize); + } + uc = ((ms_unit_t *)mdrec->record)->c; + mdrec->dfunc = &process_stripe; + mdrec->un_self_id = uc.un_self_id; + mdrec->has_parent = MD_HAS_PARENT( + uc.un_parent); + break; + case MDDB_F_MIRROR: + if (is_32bit_record) { + mm_unit32_od_t *small_un; + mm_unit_t *big_un; + + small_un = (mm_unit32_od_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (mm_unit_t); + big_un = (void *)Zalloc(newreqsize); + mirror_convert((caddr_t)small_un, + (caddr_t)big_un, SMALL_2_BIG); + mdrec->record = (void *)big_un; + } else { + mm_unit_t *big_un; + + big_un = (mm_unit_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (mm_unit_t); + mdrec->record = (void *)Zalloc(newreqsize); + bcopy(big_un, mdrec->record, newreqsize); + } + uc = ((mm_unit_t *)mdrec->record)->c; + mdrec->dfunc = &process_mirror; + mdrec->un_self_id = uc.un_self_id; + mdrec->has_parent = MD_HAS_PARENT( + uc.un_parent); + break; + case MDDB_F_RAID: + if (is_32bit_record) { + mr_unit32_od_t *small_un; + mr_unit_t *big_un; + uint_t ncol; + + small_un = (mr_unit32_od_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + ncol = small_un->un_totalcolumncnt; + newreqsize = sizeof (mr_unit_t) + + ((ncol - 1) * sizeof (mr_column_t)); + big_un = (void *)Zalloc(newreqsize); + raid_convert((caddr_t)small_un, + (caddr_t)big_un, SMALL_2_BIG); + mdrec->record = (void *)big_un; + } else { + mr_unit_t *big_un; + uint_t ncol; + + big_un = (mr_unit_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + ncol = big_un->un_totalcolumncnt; + newreqsize = sizeof (mr_unit_t) + + ((ncol - 1) * sizeof (mr_column_t)); + mdrec->record = (void *)Zalloc(newreqsize); + bcopy(big_un, mdrec->record, newreqsize); + } + uc = ((mr_unit_t *)mdrec->record)->c; + mdrec->dfunc = &process_raid; + mdrec->un_self_id = uc.un_self_id; + mdrec->has_parent = MD_HAS_PARENT( + uc.un_parent); + break; + case MDDB_F_TRANS_MASTER: + if (is_32bit_record) { + mt_unit32_od_t *small_un; + mt_unit_t *big_un; + + small_un = (mt_unit32_od_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (mt_unit_t); + big_un = (void *)Zalloc(newreqsize); + trans_master_convert((caddr_t)small_un, + (caddr_t)big_un, SMALL_2_BIG); + mdrec->record = (void *)big_un; + } else { + mt_unit_t *big_un; + + big_un = (mt_unit_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (mt_unit_t); + mdrec->record = (void *)Zalloc(newreqsize); + bcopy(big_un, mdrec->record, newreqsize); + } + uc = ((mt_unit_t *)mdrec->record)->c; + mdrec->dfunc = &process_trans; + mdrec->un_self_id = uc.un_self_id; + mdrec->has_parent = MD_HAS_PARENT( + uc.un_parent); + break; + case MDDB_F_HOTSPARE: + if (is_32bit_record) { + hot_spare32_od_t *small_un; + hot_spare_t *big_un; + + small_un = (hot_spare32_od_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (hot_spare_t); + big_un = (void *)Zalloc(newreqsize); + hs_convert((caddr_t)small_un, + (caddr_t)big_un, SMALL_2_BIG); + mdrec->record = (void *)big_un; + } else { + hot_spare_t *big_un; + + big_un = (hot_spare_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (hot_spare_t); + mdrec->record = (void *)Zalloc(newreqsize); + bcopy(big_un, mdrec->record, newreqsize); + } + hs = (hot_spare_t *)mdrec->record; + mdrec->dfunc = &process_hotspare; + mdrec->un_self_id = NULL; + mdrec->hs_record_id = hs->hs_record_id; + mdrec->has_parent = 1; + break; + case MDDB_F_HOTSPARE_POOL: + /* + * Ondisk and incore records are always same size. + * Also, hotspare pools will always be toplevel + * metadevices, so we don't need to store a + * hsp_self_id. + */ + hsp = (hot_spare_pool_ond_t *)((uintptr_t)rbp + + (sizeof (mddb_rb_t) - sizeof (int))); + newreqsize = sizeof (hot_spare_pool_ond_t) + + (sizeof (mddb_recid_t) * hsp->hsp_nhotspares); + mdrec->record = (void *)Zalloc(newreqsize); + bcopy(hsp, mdrec->record, newreqsize); + hsp = (hot_spare_pool_ond_t *)mdrec->record; + mdrec->dfunc = &process_hotspare_pool; + mdrec->un_self_id = NULL; + mdrec->has_parent = 0; + break; + /* All valid cases have been dealt with */ + default: + (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); + return (-1); + } + + /* + * If metadevice record has an entry in the NM namespace + * then it is copied into the mdrec->n_name field. + */ + if (mdrec->un_self_id != NULL) { + for (nmname = &nm_record->r_name[0]; nmname->n_key != 0; + /*LINTED*/ + nmname = (struct nm_name *)((char *)nmname + + NAMSIZ(nmname))) { + /* + * Matching the un_self_id for the record to the + * n_minor name in the NM record, to extract the + * metadevice name if it is in the namespace + */ + if ((nmname->n_minor) == (uc.un_self_id)) { + (*mdrec).n_key = nmname->n_key; + uname = Strdup(nmname->n_name); + mdrec->n_name = uname; + break; + } + } + } + + /* + * If the metadevice name is not in the namespace, then + * then we will generate the name from the minor number + * for the metadevice. In the case of records for a hotspare + * pool we use hsp_self_id, otherwise we use un_self_id. + */ + if (uname == NULL) { + if (mdrec->md_type == MDDB_F_HOTSPARE_POOL) { + uname = Malloc(MAXSIZEMDRECNAME); + (void) sprintf(uname, "hsp%03u", + HSP_ID(hsp->hsp_self_id)); + mdrec->n_name = uname; + } else if (mdrec->md_type != MDDB_F_HOTSPARE) { + /* + * Generate the metadevice name for all other records + * (except for hotspares, because hotspares can only + * be physical devices.) + */ + uname = Malloc(MAXSIZEMDRECNAME); + (void) sprintf(uname, "d%lu", + MD_MIN2UNIT(mdrec->un_self_id)); + mdrec->n_name = uname; + } + } + + return (0); +} + + +/* + * read_mdrecord() + * + * Reads the mddb_rb32_od_t or mddb_rb_t and the associated metadevice record + * from the disk. Runs magic, checksum, and revision checks on the record + * block. + * + * Returns: + * < 0 for failure + * 0 for success + * + */ +static int +read_mdrecord( + md_im_rec_t **mdimpp, + mddb_mb_t *mbp, + mddb_rb_t *nm, + mddb_de_t *dep, + char *diskname, + int fd, + md_timeval32_t *lastaccess, + md_error_t *ep +) +{ + int cnt, rval = 0; + daddr_t pblk; + md_im_rec_t *tmp_mdrec; + void *rbp = NULL; + char *rbp_tmp = NULL; + mddb_rb32_t *rbp_32; + mddb_rb_t *rbp_64; + crc_skip_t *skip = NULL; + int is_32bit_record = 0; + + tmp_mdrec = Zalloc(sizeof (md_im_rec_t)); + rbp = (void *)Zalloc(dbtob(dep->de_blkcount)); + rbp_tmp = (char *)rbp; + + /* Read in the appropriate record and return configurations */ + for (cnt = 0; cnt < dep->de_blkcount; cnt++) { + if ((pblk = getphysblk(dep->de_blks[cnt], mbp)) < 0) { + rval = mdmddberror(ep, MDE_DB_BLKRANGE, + NODEV32, MD_LOCAL_SET, + dep->de_blks[cnt], diskname); + return (rval); + } + + if (lseek(fd, (off_t)dbtob(pblk), SEEK_SET) < 0) { + rval = mdsyserror(ep, errno, diskname); + return (rval); + } + + if (read(fd, rbp_tmp, DEV_BSIZE) != DEV_BSIZE) { + rval = mdsyserror(ep, errno, diskname); + return (rval); + } + + rbp_tmp += DEV_BSIZE; + } + tmp_mdrec->md_type = dep->de_flags; + + /* + * The only place to discover whether or not the record is a + * 32bit or 64bit record is from the record's rb_revision field. + * The mddb_rb_t and mddb_rb32_t structures are identical for the + * following fields: + * rb_magic, rb_revision, rb_checksum, and rb_checksum_fiddle. + * So we can assume that the record is a 32bit structure when we + * check the record's magic number and revision and when we calculate + * the records checksum. + */ + rbp_32 = (mddb_rb32_t *)rbp; + + /* + * Checking the magic number for the record block. + */ + if (rbp_32->rb_magic != MDDB_MAGIC_RB) { + rval = -1; + (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); + goto out; + } + + /* + * Checking the revision for the record block. Must match either + * revision for the current 64bit or 32bit record block. Also, + * setting the flag for whether or not it is a 32bit record. + */ + if (revchk(MDDB_REV_RB, rbp_32->rb_revision) == 0) { + is_32bit_record = 1; + } else if (revchk(MDDB_REV_RB64, rbp_32->rb_revision) != 0) { + rval = -1; + (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); + goto out; + } + + /* + * Calculating the checksum for this record block. Need + * to skip the rb's checksum fiddle. + */ + skip = (crc_skip_t *)Malloc(sizeof (crc_skip_t)); + skip->skip_next = NULL; + skip->skip_offset = offsetof(mddb_rb_t, rb_checksum_fiddle); + skip->skip_size = 3 * sizeof (uint_t); + if (crcchk(rbp_32, &rbp_32->rb_checksum, dep->de_recsize, skip)) { + rval = -1; + (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); + goto out; + } + + /* mddb_rb_t and mddb_rb32_t differ before the rb_timestamp field */ + if (!is_32bit_record) { + if ((*lastaccess).tv_sec < rbp_32->rb_timestamp.tv_sec) { + *lastaccess = rbp_32->rb_timestamp; + } else if ((*lastaccess).tv_sec == + rbp_32->rb_timestamp.tv_sec) { + if ((*lastaccess).tv_usec < + rbp_32->rb_timestamp.tv_usec) + *lastaccess = rbp_32->rb_timestamp; + } + } else { + rbp_64 = (mddb_rb_t *)rbp; + if ((*lastaccess).tv_sec < rbp_64->rb_timestamp.tv_sec) { + *lastaccess = rbp_64->rb_timestamp; + } else if ((*lastaccess).tv_sec == + rbp_64->rb_timestamp.tv_sec) { + if ((*lastaccess).tv_usec < + rbp_64->rb_timestamp.tv_usec) + *lastaccess = rbp_64->rb_timestamp; + } + } + + /* Populates the fields in md_im_rec_t *tmp_mdrec. */ + rval = extract_mduser_data(nm, tmp_mdrec, rbp, is_32bit_record, ep); + if (rval < 0) + goto out; + + /* Adding record to the head of the list of all metadevices. */ + tmp_mdrec->prev = NULL; + if (*mdimpp == NULL) { + tmp_mdrec->next = NULL; + *mdimpp = tmp_mdrec; + } else { + (*mdimpp)->prev = tmp_mdrec; + tmp_mdrec->next = *mdimpp; + *mdimpp = tmp_mdrec; + } + +out: + /* Free the skip list */ + while (skip) { + crc_skip_t *skip_rm = skip; + + skip = skip->skip_next; + Free(skip_rm); + } + + if (rbp) + Free(rbp); + + return (rval); +} + + +/* + * read_all_mdrecords() + * + * Reads the directory block and directory entries. + * Runs magic, checksum, and revision checks on the directory block. + * + * Returns: + * < 0 for failure + * 0 for success + */ +static int +read_all_mdrecords( + md_im_rec_t **mdimpp, + mddb_mb_t *mbp, + mddb_lb_t *lbp, + mddb_rb_t *nm, + mdname_t *rsp, + int fd, + md_timeval32_t *lastaccess, + md_error_t *ep +) +{ + int dbblk, rval = 0; + char db[DEV_BSIZE]; + mddb_de_t *dep; + int desize; + /*LINTED*/ + mddb_db_t *dbp = (mddb_db_t *)&db; + + /* Read in all directory blocks */ + for (dbblk = lbp->lb_dbfirstblk; + dbblk != 0; + dbblk = dbp->db_nextblk) { + + if ((rval = read_database_block(ep, fd, mbp, dbblk, + dbp, sizeof (db))) <= 0) + goto out; + + /* + * Set ep with error code for MDE_DB_NODB. This is the + * error code used in the kernel when there is a problem + * with reading records in. Checks the magic number, the + * revision, and the checksum for each directory block. + */ + if (dbp->db_magic != MDDB_MAGIC_DB) { + rval = -1; + (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); + goto out; + } + + if (revchk(MDDB_REV_DB, dbp->db_revision)) { + rval = -1; + (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); + goto out; + } + + if (crcchk(dbp, &dbp->db_checksum, MDDB_BSIZE, NULL)) { + rval = -1; + (void) mdmddberror(ep, MDE_DB_NODB, 0, 0, 0, NULL); + goto out; + } + + /* + * If db timestamp is more recent than the previously recorded + * last modified timestamp, then update last modified. + */ + if ((*lastaccess).tv_sec < dbp->db_timestamp.tv_sec) { + *lastaccess = dbp->db_timestamp; + } else if ((*lastaccess).tv_sec == dbp->db_timestamp.tv_sec) { + if ((*lastaccess).tv_usec < dbp->db_timestamp.tv_usec) + *lastaccess = dbp->db_timestamp; + } + + /* Creates dep list of all directory entries in the db */ + if (dbp->db_firstentry != NULL) { + /* LINTED */ + dep = (mddb_de_t *)((caddr_t)(&dbp->db_firstentry) + + sizeof (dbp->db_firstentry)); + dbp->db_firstentry = dep; + while (dep && dep->de_next) { + desize = sizeof (*dep) - + sizeof (dep->de_blks) + + sizeof (daddr_t) * dep->de_blkcount; + /* LINTED */ + dep->de_next = (mddb_de_t *) + ((caddr_t)dep + desize); + dep = dep->de_next; + } + } + + /* + * Process all directory entries in the directory block. + * For each directory entry, read_mdrec is called to read + * in the record data. + */ + for (dep = dbp->db_firstentry; dep != NULL; + dep = dep->de_next) { + + /* + * de_flags is set to the type of metadevice. + * If directory entry does not correspond to a + * specific metadevice then it is set to zero. + * All namespace records(NM, SHR_NM, DID_SHR_NM) have a + * value of zero in their de_flags field. + */ + if ((dep->de_flags != 0)&& + (dep->de_flags != MDDB_F_OPT) && + (dep->de_flags != MDDB_F_TRANS_LOG) && + (dep->de_flags != MDDB_F_CHANGELOG)) { + rval = read_mdrecord(mdimpp, mbp, nm, dep, + rsp->cname, fd, lastaccess, ep); + if (rval < 0) + goto out; + } + } + } + +out: + return (rval); +} + + +/* + * report_metastat_info() + * + * Generates the metastat -c output. Also, updates the global variable + * for a last accessed timestamp. + * + * Returns: + * < 0 for failure + * 0 for success + * + */ +int +report_metastat_info( + mddb_mb_t *mb, + mddb_lb_t *lbp, + mddb_rb_t *nm, + pnm_rec_t **pnm, + mdname_t *rsp, + int fd, + md_timeval32_t *lastaccess, + md_error_t *ep +) +{ + int rval = 0; + /* list of all metadevices in diskset */ + md_im_rec_t *mdimp = NULL; + md_im_rec_t *tmp_mdrec, *rm_mdrec; + + /* Read in metadevice records and add entries to mdimp list. */ + rval = read_all_mdrecords(&mdimp, mb, lbp, nm, rsp, fd, lastaccess, + ep); + if (rval < 0) + goto out; + + /* Adding a fake record to the head of the list of all metadevices. */ + if (mdimp != NULL) { + tmp_mdrec = Zalloc(sizeof (md_im_rec_t)); + tmp_mdrec->prev = NULL; + mdimp->prev = tmp_mdrec; + tmp_mdrec->next = mdimp; + mdimp = tmp_mdrec; + } + + /* Calling functions to process all metadevices on mdimp list */ + process_toplevel_devices(&mdimp, *pnm, MDDB_F_SOFTPART); + process_toplevel_devices(&mdimp, *pnm, MDDB_F_TRANS_MASTER); + process_toplevel_devices(&mdimp, *pnm, MDDB_F_MIRROR); + process_toplevel_devices(&mdimp, *pnm, MDDB_F_RAID); + process_toplevel_devices(&mdimp, *pnm, MDDB_F_STRIPE); + process_toplevel_devices(&mdimp, *pnm, MDDB_F_HOTSPARE_POOL); + (void) printf("\n"); + +out: + /* + * If mdreclist is not null, then this will walk through all + * elements and free them. + */ + tmp_mdrec = mdimp; + while (tmp_mdrec != NULL) { + rm_mdrec = tmp_mdrec; + tmp_mdrec = tmp_mdrec->next; + if (rm_mdrec->record != NULL) + Free(rm_mdrec->record); + if (rm_mdrec->n_name != NULL) + Free(rm_mdrec->n_name); + Free(rm_mdrec); + } + + free_pnm_rec_list(pnm); + return (rval); +} diff --git a/usr/src/lib/lvm/libmeta/spec/meta.spec b/usr/src/lib/lvm/libmeta/spec/meta.spec index 48d7d2b30e..10faf4d99b 100644 --- a/usr/src/lib/lvm/libmeta/spec/meta.spec +++ b/usr/src/lib/lvm/libmeta/spec/meta.spec @@ -950,7 +950,7 @@ function meta_list_drives version SUNWprivate_1.1 end -function meta_get_set_info +function meta_get_and_report_set_info version SUNWprivate_1.1 end @@ -958,6 +958,22 @@ function meta_prune_cnames version SUNWprivate_1.1 end +function print_concise_entry +version SUNWprivate_1.1 +end + +function meta_get_raid_col_state +version SUNWprivate_1.1 +end + +function meta_get_stripe_state +version SUNWprivate_1.1 +end + +function meta_get_hs_state +version SUNWprivate_1.1 +end + function meta_rel_own version SUNWprivate_1.1 end diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 831dcb585a..69a29625d4 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -822,9 +822,11 @@ UFS_OBJS += ufs_alloc.o ufs_bmap.o ufs_dir.o ufs_xattr.o \ # LVM modules # MD_OBJS += md.o md_error.o md_ioctl.o md_mddb.o md_names.o \ - md_med.o md_rename.o md_subr.o md_convert.o + md_med.o md_rename.o md_subr.o -MD_DERIVED_OBJS = md_crc.o metamed_xdr.o meta_basic_xdr.o +MD_COMMON_OBJS = md_convert.o md_crc.o md_revchk.o + +MD_DERIVED_OBJS = metamed_xdr.o meta_basic_xdr.o SOFTPART_OBJS += sp.o sp_ioctl.o diff --git a/usr/src/uts/common/io/lvm/md/md_mddb.c b/usr/src/uts/common/io/lvm/md/md_mddb.c index 4504db2bd8..94706cafe5 100644 --- a/usr/src/uts/common/io/lvm/md/md_mddb.c +++ b/usr/src/uts/common/io/lvm/md/md_mddb.c @@ -506,18 +506,6 @@ freebuffer( } } -int -revchk( - uint_t mine, - uint_t data -) -{ - if ((MDDB_REV_MAJOR & mine) != (MDDB_REV_MAJOR & data)) - return (1); - if ((MDDB_REV_MINOR & mine) < (MDDB_REV_MINOR & data)) - return (1); - return (0); -} static void blkbusy( diff --git a/usr/src/uts/common/io/lvm/md/md_subr.c b/usr/src/uts/common/io/lvm/md/md_subr.c index d3efb5c731..e384916f85 100644 --- a/usr/src/uts/common/io/lvm/md/md_subr.c +++ b/usr/src/uts/common/io/lvm/md/md_subr.c @@ -67,6 +67,8 @@ #include <sys/sysevent/eventdefs.h> #include <sys/sysevent/svm.h> +#include <sys/lvm/md_basic.h> + /* * Machine specific Hertz is kept here @@ -3629,65 +3631,6 @@ md_biodone(struct buf *pb) biodone(pb); } -/* - * The following constants are not defined in a 32 bit environment. - * We definitely need them also in a 32bit environment, - * since we're always dealing with 64 bit wide devices - */ -#ifndef NBITSMINOR64 -#define NBITSMINOR64 32 -#endif /* NBITSMINOR64 */ - -#ifndef MAXMAJ64 -#define MAXMAJ64 0xfffffffful -#endif /* MAXMAJ64 */ - -#ifndef MAXMIN64 -#define MAXMIN64 0xfffffffful -#endif /* MAXMAJ64 */ - - -/* - * Driver private devt expansion routine - * INPUT: dev a 64 bit container holding either a 32 bit or a 64 bit device - * OUTPUT: always an expanded 64 bit device, even if we are running in a - * 32 bit Kernel. - */ -md_dev64_t -md_expldev(md_dev64_t dev) -{ - minor_t minor; - major_t major = (major_t)(dev >> NBITSMINOR64) & MAXMAJ64; - - /* Here we were given a 64bit dev, return unchanged */ - if (major != (major_t)0) - return (dev); - /* otherwise we were given a 32 bit dev */ - major = (major_t)dev >> NBITSMINOR32 & MAXMAJ32; - minor = (minor_t)dev & MAXMIN32; - return (((md_dev64_t)major << NBITSMINOR64) | minor); -} - - -/* - * Driver private devt compact routine - * INPUT: dev a 64 bit container holding either a 32 bit or a 64 bit device - * OUTPUT: always a compacted 32 bit device, even if we are running in a - * 64 bit Kernel. - */ -dev32_t -md_cmpldev(md_dev64_t dev) -{ - minor_t minor; - major_t major = (major_t)(dev >> NBITSMINOR64) & MAXMAJ64; - - if (major == 0) { - /* Here we were given a 32bit dev, return unchanged */ - return ((dev32_t)dev); - } - minor = (minor_t)dev & MAXMIN32; - return (((dev32_t)major << NBITSMINOR32) | minor); -} /* * Driver special private devt handling routine diff --git a/usr/src/uts/common/sys/lvm/md_hotspares.h b/usr/src/uts/common/sys/lvm/md_hotspares.h index 3121f8a757..7e151c946e 100644 --- a/usr/src/uts/common/sys/lvm/md_hotspares.h +++ b/usr/src/uts/common/sys/lvm/md_hotspares.h @@ -20,7 +20,7 @@ * CDDL HEADER END */ /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -118,13 +118,19 @@ typedef struct hot_spare32_od { #pragma pack() #endif +/* + * The pads are necessary for the hot_spare_t structure to be interpreted + * correctly in userland on the amd64 arch. + */ typedef struct hot_spare { uint_t hs_revision; /* revision number */ mddb_recid_t hs_record_id; /* db record id */ md_dev64_t hs_devnum; /* hs device number */ mdkey_t hs_key; /* namespace key */ + int hs_pad1; diskaddr_t hs_start_blk; /* hs starting block */ int hs_has_label; /* hs has a label */ + int hs_pad2; diskaddr_t hs_number_blks; /* hs # of blocks */ hotspare_states_t hs_state; /* hs state */ int hs_refcount; /* # hsp using the hs */ diff --git a/usr/src/uts/common/sys/lvm/mdvar.h b/usr/src/uts/common/sys/lvm/mdvar.h index b3512f9e02..046e1b3ede 100644 --- a/usr/src/uts/common/sys/lvm/mdvar.h +++ b/usr/src/uts/common/sys/lvm/mdvar.h @@ -832,6 +832,11 @@ extern void *getshared_name(set_t, mdkey_t, int); #endif /* _KERNEL */ + +/* externals from md_revchk.c */ +extern int revchk(uint_t my_rev, uint_t data); + + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/intel/md/Makefile b/usr/src/uts/intel/md/Makefile index fce1e2d107..aaf7bd8bf3 100644 --- a/usr/src/uts/intel/md/Makefile +++ b/usr/src/uts/intel/md/Makefile @@ -21,8 +21,8 @@ # # # uts/intel/md/Makefile -# Copyright (c) 1999-2001 by Sun Microsystems, Inc. -# All rights reserved. +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" # @@ -41,8 +41,10 @@ UTSBASE = ../.. # MODULE = md OBJECTS = $(MD_OBJS:%=$(OBJS_DIR)/%) +OBJECTS += $(MD_COMMON_OBJS:%=$(OBJS_DIR)/%) OBJECTS += $(MD_DERIVED_OBJS:%=$(OBJS_DIR)/%) LINTS = $(MD_OBJS:%.o=$(LINTS_DIR)/%.ln) +LINTS += $(MD_COMMON_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) CONF_SRCDIR = $(UTSBASE)/common/io/lvm/md diff --git a/usr/src/uts/sparc/md/Makefile b/usr/src/uts/sparc/md/Makefile index 79a326ccc3..c22554941c 100644 --- a/usr/src/uts/sparc/md/Makefile +++ b/usr/src/uts/sparc/md/Makefile @@ -21,7 +21,7 @@ # # # uts/sparc/md/Makefile -# Copyright 2004 Sun Microsystems, Inc. All rights reserved. +# Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -41,8 +41,10 @@ UTSBASE = ../.. # MODULE = md OBJECTS = $(MD_OBJS:%=$(OBJS_DIR)/%) +OBJECTS += $(MD_COMMON_OBJS:%=$(OBJS_DIR)/%) OBJECTS += $(MD_DERIVED_OBJS:%=$(OBJS_DIR)/%) LINTS = $(MD_OBJS:%.o=$(LINTS_DIR)/%.ln) +LINTS += $(MD_COMMON_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) CONF_SRCDIR = $(UTSBASE)/common/io/lvm/md |