summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authormw145384 <none@none>2005-10-21 13:01:21 -0700
committermw145384 <none@none>2005-10-21 13:01:21 -0700
commit4745263a792e84bbd9e36b3ceb07d1275762cf9b (patch)
treeca16981779526d27075b6038cb54dc410d36e10b /usr/src
parentaae21359c9c25c5100c4853afd7334521ede3276 (diff)
downloadillumos-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.c231
-rw-r--r--usr/src/cmd/lvm/util/metastat.c119
-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.c62
-rw-r--r--usr/src/head/meta.h46
-rw-r--r--usr/src/lib/lvm/libmeta/Makefile.com5
-rw-r--r--usr/src/lib/lvm/libmeta/common/meta_import.c476
-rw-r--r--usr/src/lib/lvm/libmeta/common/meta_statconcise.c1867
-rw-r--r--usr/src/lib/lvm/libmeta/spec/meta.spec18
-rw-r--r--usr/src/uts/common/Makefile.files6
-rw-r--r--usr/src/uts/common/io/lvm/md/md_mddb.c12
-rw-r--r--usr/src/uts/common/io/lvm/md/md_subr.c61
-rw-r--r--usr/src/uts/common/sys/lvm/md_hotspares.h8
-rw-r--r--usr/src/uts/common/sys/lvm/mdvar.h5
-rw-r--r--usr/src/uts/intel/md/Makefile6
-rw-r--r--usr/src/uts/sparc/md/Makefile4
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