summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorjeanm <none@none>2006-05-06 10:47:51 -0700
committerjeanm <none@none>2006-05-06 10:47:51 -0700
commitda83352438a4a62b87fcb6fd1583e3a70aa31bb8 (patch)
tree2ed9be63db473a2144198071f61b16c67f50df86 /usr/src/cmd
parent1e3549a6454dbbb2d27b0f1fdb707b1d24b7141b (diff)
downloadillumos-gate-da83352438a4a62b87fcb6fd1583e3a70aa31bb8.tar.gz
4964366 metaimport should handle partial disksets
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/lvm/rpc.metad/metad_svc_subr.c196
-rw-r--r--usr/src/cmd/lvm/util/metaimport.c525
-rw-r--r--usr/src/cmd/lvm/util/metaset.c26
3 files changed, 603 insertions, 144 deletions
diff --git a/usr/src/cmd/lvm/rpc.metad/metad_svc_subr.c b/usr/src/cmd/lvm/rpc.metad/metad_svc_subr.c
index 92f6d1c490..0d92faf3e2 100644
--- a/usr/src/cmd/lvm/rpc.metad/metad_svc_subr.c
+++ b/usr/src/cmd/lvm/rpc.metad/metad_svc_subr.c
@@ -132,11 +132,13 @@ add_sideno_sidenm(
*/
if (MD_MNSET_DESC(sd)) {
if (add_name(local_sp, sideno, local_key,
- sn->dname, sn->mnum, sn->cname, ep) == -1)
+ sn->dname, sn->mnum, sn->cname, NULL, NULL,
+ ep) == -1)
return (-1);
} else {
if (add_name(local_sp, sideno+SKEW, local_key,
- sn->dname, sn->mnum, sn->cname, ep) == -1)
+ sn->dname, sn->mnum, sn->cname, NULL, NULL,
+ ep) == -1)
return (-1);
}
} else
@@ -597,7 +599,8 @@ add_sidenamelist(
*/
if (nodeid == sn->sideno) {
if ((err = add_name(local_sp, sn->sideno, key,
- sn->dname, sn->mnum, sn->cname, ep)) == -1)
+ sn->dname, sn->mnum, sn->cname,
+ NULL, NULL, ep)) == -1)
return (-1);
key = (mdkey_t)err;
break;
@@ -620,7 +623,8 @@ add_sidenamelist(
if (sn->sideno != thisside)
continue;
if ((err = add_name(local_sp, sn->sideno+SKEW, key,
- sn->dname, sn->mnum, sn->cname, ep)) == -1)
+ sn->dname, sn->mnum, sn->cname, NULL,
+ NULL, ep)) == -1)
return (-1);
key = (mdkey_t)err;
break;
@@ -635,7 +639,8 @@ add_sidenamelist(
if (sn->sideno == thisside)
continue;
if ((err = add_name(local_sp, sn->sideno+SKEW, key,
- sn->dname, sn->mnum, sn->cname, ep)) == -1)
+ sn->dname, sn->mnum, sn->cname, NULL, NULL,
+ ep)) == -1)
return (-1);
key = (mdkey_t)err;
}
@@ -647,7 +652,8 @@ add_sidenamelist(
sn = dn->side_names;
if (sn) {
if ((err = add_name(local_sp, sn->sideno, key,
- sn->dname, sn->mnum, sn->cname, ep)) == -1)
+ sn->dname, sn->mnum, sn->cname,
+ NULL, NULL, ep)) == -1)
return (-1);
key = (mdkey_t)err;
}
@@ -658,6 +664,139 @@ add_sidenamelist(
return (0);
}
+/*
+ * imp_adddrvs
+ * This is a version of adddrvs that is specific to the
+ * metaimport command. Due to the unavailability of some disks,
+ * information needs to be obtained about the disk from the devid so
+ * it can eventually be passed down to add_sidenamelist.
+ * Go ahead and set drive state to MD_DR_OK here so that no
+ * later RPC is needed to set OK where UNRLSV_REPLICATED could
+ * be cleared. Set record is still set to MD_SR_ADD which will force
+ * a cleanup of the set in case of panic.
+ */
+void
+imp_adddrvs(
+ char *setname,
+ md_drive_desc *dd,
+ md_timeval32_t timestamp,
+ ulong_t genid,
+ md_error_t *ep
+)
+{
+ mddb_userreq_t req;
+ md_drive_record *dr, *tdr;
+ md_set_record *sr;
+ md_drive_desc *p;
+ mddrivename_t *dn;
+ mdname_t *np;
+ md_dev64_t dev;
+ md_error_t xep = mdnullerror;
+ char *minorname = NULL;
+ ddi_devid_t devidp = NULL;
+ mdsidenames_t *sn;
+ mdsetname_t *local_sp;
+
+
+ if ((local_sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
+ return;
+ }
+
+ if ((sr = getsetbyname(setname, ep)) == NULL)
+ return;
+
+ for (p = dd; p != NULL; p = p->dd_next) {
+ uint_t rep_slice;
+ int ret = 0;
+
+ dn = p->dd_dnp;
+
+ /*
+ * We need the minorname and devid string decoded from the
+ * devid to add the sidename for this drive to the
+ * local set.
+ */
+ ret = devid_str_decode(dn->devid, &devidp, &minorname);
+ if (ret != 0) {
+ /* failed to decode the devid */
+ goto out;
+ }
+
+ sn = dn->side_names;
+ if (sn == NULL) {
+ dn->side_names_key = MD_KEYWILD;
+ continue;
+ }
+
+ if ((dn->side_names_key = add_name(local_sp, SKEW, MD_KEYWILD,
+ sn->dname, sn->mnum, sn->cname, minorname, devidp,
+ ep)) == -1) {
+ devid_free(devidp);
+ devid_str_free(minorname);
+ goto out;
+ }
+
+ devid_free(devidp);
+ devid_str_free(minorname);
+
+ /* Create the drive record */
+ (void) memset(&req, 0, sizeof (req));
+ METAD_SETUP_DR(MD_DB_CREATE, 0);
+ req.ur_size = sizeof (*dr);
+ if (metaioctl(MD_DB_USERREQ, &req, &req.ur_mde, NULL) != 0) {
+ (void) mdstealerror(ep, &req.ur_mde);
+ goto out;
+ }
+
+ /* Fill in the drive record values */
+ dr = Zalloc(sizeof (*dr));
+ dr->dr_selfid = req.ur_recid;
+ dr->dr_dbcnt = p->dd_dbcnt;
+ dr->dr_dbsize = p->dd_dbsize;
+ dr->dr_key = dn->side_names_key;
+
+ dr->dr_ctime = timestamp;
+ dr->dr_genid = genid;
+ dr->dr_revision = MD_DRIVE_RECORD_REVISION;
+ dr->dr_flags = MD_DR_OK;
+ if (p->dd_flags & MD_DR_UNRSLV_REPLICATED) {
+ dr->dr_flags |= MD_DR_UNRSLV_REPLICATED;
+ sr->sr_flags |= MD_SR_UNRSLV_REPLICATED;
+ }
+
+ /* Link the drive records and fill in in-core data */
+ dr_cache_add(sr, dr);
+
+ dev = NODEV64;
+ if ((meta_replicaslice(dn, &rep_slice, &xep) == 0) &&
+ ((np = metaslicename(dn, rep_slice, &xep)) != NULL))
+ dev = np->dev;
+ else
+ mdclrerror(&xep);
+
+ SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_REMOVE, SVM_TAG_DRIVE,
+ MD_LOCAL_SET, dev);
+ SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_ADD, SVM_TAG_DRIVE,
+ sr->sr_setno, dev);
+ }
+
+ /* Commit all the records atomically */
+ commitset(sr, TRUE, ep);
+ free_sr(sr);
+ return;
+
+out:
+ /* If failures, remove drive records. */
+ dr = tdr = sr->sr_drivechain;
+ while (dr != NULL) {
+ tdr = dr->dr_next;
+ if (del_name(local_sp, 0, dr->dr_key, &xep))
+ mdclrerror(&xep);
+ sr_del_drv(sr, dr->dr_selfid);
+ dr = tdr;
+ }
+}
+
static void
adddrvs(
char *setname,
@@ -836,6 +975,51 @@ mdrpc_adddrvs_2_svc(
}
}
+/*
+ * add 1 or more drive records to a set when importing.
+ */
+bool_t
+mdrpc_imp_adddrvs_2_svc(
+ mdrpc_drives_2_args *args,
+ mdrpc_generic_res *res,
+ struct svc_req *rqstp /* RPC stuff */
+)
+{
+ mdrpc_drives_2_args_r1 *v2_args;
+ md_error_t *ep = &res->status;
+ int err;
+ int op_mode = W_OK;
+
+ switch (args->rev) {
+ case MD_METAD_ARGS_REV_1:
+ v2_args = &args->mdrpc_drives_2_args_u.rev1;
+ if (v2_args == NULL) {
+ return (FALSE);
+ }
+ break;
+ default:
+ return (FALSE);
+ }
+
+ /* setup, check permissions */
+ (void) memset(res, 0, sizeof (*res));
+ if ((err = svc_init(rqstp, op_mode, ep)) < 0)
+ return (FALSE);
+ else if (err != 0)
+ return (TRUE);
+
+ if (check_set_lock(op_mode, v2_args->cl_sk, ep))
+ return (TRUE);
+
+ /* doit */
+ imp_adddrvs(v2_args->sp->setname, v2_args->drivedescs,
+ v2_args->timestamp, v2_args->genid, ep);
+
+ err = svc_fini(ep);
+
+ return (TRUE);
+}
+
static void
addhosts(
char *setname,
diff --git a/usr/src/cmd/lvm/util/metaimport.c b/usr/src/cmd/lvm/util/metaimport.c
index 0ec9adfeb1..231be20eed 100644
--- a/usr/src/cmd/lvm/util/metaimport.c
+++ b/usr/src/cmd/lvm/util/metaimport.c
@@ -2,9 +2,8 @@
* 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.
+ * Common Development and Distribution License (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.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -39,7 +38,7 @@
#include <sys/lvm/md_names.h>
#include <sdssc.h>
-static md_im_drive_info_t *overlap_disks = NULL;
+static md_im_drive_info_t *overlap_disks;
static void
usage(mdsetname_t *sp, char *string)
@@ -79,51 +78,123 @@ print_version(mdsetname_t *sp)
static int
set_disk_overlap(md_im_set_desc_t *misp)
{
-
- md_im_set_desc_t *next, *isp = misp;
- md_im_drive_info_t *set_dr, *next_set_dr, **chain;
- int is_overlap = 0;
-
+ md_im_set_desc_t *next, *isp = misp;
+ md_im_drive_info_t *set_dr, *next_set_dr, **chain;
+ int is_overlap = 0;
+ md_im_drive_info_t *good_disk = NULL;
+ md_im_drive_info_t *d;
+ md_timeval32_t gooddisktime;
+ int disk_not_available = 0;
+ /*
+ * There are 2 ways we could get an "overlap" disk.
+ * One is if the ctd's are the same. The other is if
+ * the setcreatetimestamp on the disk doesn't agree with the
+ * "good" disk in the set. However, if we have a disk that is
+ * unavailable and the other instance of the ctd is available we
+ * really don't have a conflict. It's just that the unavailable ctd
+ * is it's "old" location and the available instance is a current
+ * location.
+ */
for (; isp != NULL; isp = isp->mis_next) {
for (next = isp->mis_next; next != NULL; next = next->mis_next) {
-
for (set_dr = isp->mis_drives; set_dr != NULL;
- set_dr = set_dr->mid_next) {
-
- for (next_set_dr = next->mis_drives;
- next_set_dr != NULL;
- next_set_dr = next_set_dr->mid_next) {
- if (strcmp(set_dr->mid_dnp->cname,
- next_set_dr->mid_dnp->cname) == 0) {
+ set_dr = set_dr->mid_next) {
+ if (set_dr->mid_available == MD_IM_DISK_NOT_AVAILABLE)
+ disk_not_available = 1;
+ else
+ disk_not_available = 0;
+ for (next_set_dr = next->mis_drives; next_set_dr != NULL;
+ next_set_dr = next_set_dr->mid_next) {
+ if (disk_not_available &&
+ (next_set_dr->mid_available
+ == MD_IM_DISK_AVAILABLE))
+ continue;
+ else if (!disk_not_available &&
+ (next_set_dr->mid_available ==
+ MD_IM_DISK_NOT_AVAILABLE))
+ continue;
+ if (strcmp(set_dr->mid_dnp->cname,
+ next_set_dr->mid_dnp->cname) == 0) {
/*
- * Chain it, skip if already there
+ * Chain it, skip if
+ * already there
*/
if (overlap_disks == NULL) {
set_dr->overlap = NULL;
+ set_dr->overlapped_disk = 1;
+ next_set_dr->overlapped_disk = 1;
overlap_disks = set_dr;
} else {
for (chain = &overlap_disks;
*chain != NULL;
chain = &(*chain)->overlap) {
if (strcmp(set_dr->mid_dnp->cname,
- (*chain)->mid_dnp->cname)
- == 0)
+ (*chain)->mid_dnp->cname) == 0)
break;
}
if (*chain == NULL) {
*chain = set_dr;
set_dr->overlap = NULL;
+ set_dr->overlapped_disk = 1;
+ next_set_dr->overlapped_disk = 1;
}
}
if (!is_overlap)
is_overlap = 1;
- }
}
+ }
}
}
}
+ for (isp = misp; isp != NULL; isp = isp->mis_next) {
+ good_disk = pick_good_disk(isp);
+ if (good_disk == NULL) {
+ /* didn't find a good disk */
+ continue;
+ }
+ gooddisktime = good_disk->mid_setcreatetimestamp;
+ for (d = isp->mis_drives; d != NULL; d = d->mid_next) {
+ if (d->mid_available == MD_IM_DISK_NOT_AVAILABLE)
+ continue;
+ /*
+ * If the disk doesn't have the same set creation
+ * time as the designated "good disk" we have a
+ * time conflict/overlap situation. Mark the disk
+ * as such.
+ */
+ if ((gooddisktime.tv_usec !=
+ d->mid_setcreatetimestamp.tv_usec) ||
+ (gooddisktime.tv_sec !=
+ d->mid_setcreatetimestamp.tv_sec)) {
+ d->overlapped_disk = 1;
+ if (overlap_disks == NULL) {
+ d->overlap = NULL;
+ d->overlapped_disk = 1;
+ overlap_disks = d;
+ } else {
+ for (chain = &overlap_disks;
+ *chain != NULL;
+ chain = &(*chain)->overlap) {
+ if (strcmp(d->mid_dnp->cname,
+ (*chain)->mid_dnp->cname)
+ == 0) {
+ break;
+ }
+ }
+
+ if (*chain == NULL) {
+ *chain = d;
+ d->overlap = NULL;
+ d->overlapped_disk = 1;
+ }
+ }
+ if (!is_overlap)
+ is_overlap = 1;
+ }
+ }
+ }
return (is_overlap);
}
@@ -155,6 +226,19 @@ report_overlap_recommendation()
uint_t sliceno;
int fd = -1;
+ /*
+ * If the disk isn't available (i.e. powered off or dead)
+ * we can't read the master block timestamp and thus
+ * cannot make a recommendation as to which set it belongs to.
+ */
+ if (d->mid_available != MD_IM_DISK_AVAILABLE) {
+ (void) fprintf(stdout, " %s ", d->mid_dnp->cname);
+ (void) fprintf(stdout,
+ gettext(" - no recommendation can "
+ "be made because disk is unavailable\n"));
+ continue;
+ }
+
if (meta_replicaslice(d->mid_dnp, &sliceno, ep) != 0)
continue;
@@ -173,13 +257,174 @@ report_overlap_recommendation()
(void) close(fd);
fprintf(stdout, " %s ", d->mid_dnp->cname);
(void) fprintf(stdout, "%s: %s\n",
- gettext(" - recommend importing with set "
+ gettext(" - must import with set "
"created at "), meta_print_time((md_timeval32_t *)
(&(mbp->mb_setcreatetime))));
}
Free(mbp);
}
+/*
+ * is_first_disk is called to determine if the disk passed to it is
+ * eligible to be used as the "first disk time" in the set. It checks to
+ * see if the disk is available, on the skip list or not (thus already in
+ * an importable set) or being used by the system already.
+ * RETURN:
+ * 1 The time can be used as the first disk time
+ * 0 The time should not be used.
+ */
+static int
+is_first_disk(
+md_im_drive_info_t *d,
+mddrivenamelist_t **skiph)
+{
+ mddrivenamelist_t *slp;
+ md_error_t status = mdnullerror;
+ md_error_t *ep = &status;
+ mdsetname_t *sp = metasetname(MD_LOCAL_NAME, ep);
+
+ /*
+ * If a disk is not available there is no
+ * set creation timestamp available.
+ */
+ if (d->mid_available == MD_IM_DISK_AVAILABLE) {
+ /*
+ * We also need to make sure this disk isn't already on
+ * the skip list.
+ */
+ for (slp = *skiph; slp != NULL; slp = slp->next) {
+ if (d->mid_dnp == slp->drivenamep)
+ return (0);
+ }
+ /*
+ * And we need to make sure the drive isn't
+ * currently being used for something else
+ * like a mounted file system or a current
+ * metadevice or in a set.
+ */
+ if (meta_imp_drvused(sp, d->mid_dnp, ep)) {
+ return (0);
+ }
+ } else {
+ return (0);
+ }
+ return (1);
+}
+
+/*
+ * Input a list of disks (dnlp), find the sets that are importable, create
+ * a list of these sets (mispp), and a list of the disks within each of these
+ * sets (midp). These lists (mispp and midp) will be used by metaimport.
+ */
+static int process_disks(
+ mddrivenamelist_t *dnlp,
+ mddrivenamelist_t **skipt,
+ md_im_set_desc_t **mispp,
+ int flags,
+ int *set_count,
+ int overlap,
+ md_error_t *ep
+)
+{
+ mddrivenamelist_t *dp;
+ int rscount = 0;
+ int hasreplica;
+ md_im_set_desc_t *p;
+ md_im_drive_info_t *d;
+ mddrivenamelist_t **skiph = skipt;
+
+ /* Scan qualified disks */
+ for (dp = dnlp; dp != NULL; dp = dp->next) {
+ mddrivenamelist_t *slp;
+
+ /* is the current drive on the skip list? */
+ for (slp = *skiph; slp != NULL; slp = slp->next) {
+ if (dp->drivenamep == slp->drivenamep)
+ break;
+ }
+ /* drive on the skip list ? */
+ if (slp != NULL)
+ continue;
+
+ /*
+ * 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,
+ flags, set_count, overlap, overlap_disks, ep);
+
+ if (hasreplica < 0) {
+ mde_perror(ep, "");
+ mdclrerror(ep);
+ } else {
+
+ rscount += hasreplica;
+
+ /* Eliminate duplicate reporting */
+ if (hasreplica > 0) {
+ md_timeval32_t firstdisktime;
+
+ /*
+ * Go to the tail for the current set
+ */
+ for (p = *mispp; p->mis_next != NULL;
+ p = p->mis_next);
+
+ /*
+ * Now look for the set creation timestamp.
+ * If a disk is not available there is no
+ * set creation timestamp available so look
+ * for the first available disk to grab this
+ * information from. We also need to make
+ * sure this disk isn't already on the skip
+ * list. If so go to the next available drive.
+ * And we need to make sure the drive isn't
+ * currently being used for something else
+ * like a mounted file system or a current
+ * metadevice or in a set.
+ */
+ for (d = p->mis_drives; d != NULL;
+ d = d->mid_next) {
+ if (is_first_disk(d, skiph)) {
+ firstdisktime =
+ d->mid_setcreatetimestamp;
+ break;
+ }
+ }
+ for (d = p->mis_drives; d != NULL;
+ d = d->mid_next) {
+ /*
+ * if the mb_setcreatetime for a disk
+ * is not the same as the first disk
+ * in the set, don't put it on the
+ * skip list. This disk probably
+ * doesn't really belong in this set
+ * and we'll want to look at it again
+ * to figure out where it does belong.
+ * If the disk isn't available, there's
+ * really no point in looking at it
+ * again so put it on the skip list.
+ */
+ if (d->mid_available ==
+ MD_IM_DISK_AVAILABLE) {
+ if ((d->mid_setcreatetimestamp.
+ tv_sec != firstdisktime.
+ tv_sec) ||
+ (d->mid_setcreatetimestamp.
+ tv_usec !=
+ firstdisktime.tv_usec))
+ continue;
+ }
+ skipt =
+ meta_drivenamelist_append_wrapper(
+ skipt, d->mid_dnp);
+ }
+ }
+ }
+ }
+ return (rscount);
+}
int
main(int argc, char *argv[])
@@ -197,18 +442,18 @@ main(int argc, char *argv[])
mddrivenamelist_t *dnlp = NULL;
mddrivenamelist_t *dp;
mddrivenamelist_t *skiph = NULL;
- mddrivenamelist_t **skipt = &skiph;
int rscount = 0;
- int hasreplica;
+ md_im_set_desc_t *pass1_misp = NULL;
md_im_set_desc_t *misp = NULL;
+ md_im_set_desc_t **pass1_mispp = &pass1_misp;
md_im_set_desc_t **mispp = &misp;
mhd_mhiargs_t mhiargs = defmhiargs;
int have_multiple_sets = 0;
int force = 0;
int overlap = 0;
- int partial = 0;
uint_t imp_flags = 0;
int set_count = 0;
+ int no_quorum = 0;
/*
* Get the locale set up before calling any other routines
@@ -374,7 +619,8 @@ main(int argc, char *argv[])
char *dlist;
int sizecnt = 0;
- sizecnt += strlen(ip->drive);
+ /* add 1 for null terminator */
+ sizecnt += strlen(ip->drive) + 1;
for (dp = dnlp->next; dp != NULL; dp = dp->next) {
sizecnt += 2; /* for the ", " */
sizecnt += strlen(dp->drivenamep->cname);
@@ -383,15 +629,14 @@ main(int argc, char *argv[])
dlist = Malloc(sizecnt);
strlcpy(dlist, ip->drive, sizecnt);
- Free(ip->drive);
- dlist += strlen(ip->drive);
+ Free(ip->drive);
for (dp = dnlp->next; dp != NULL; dp = dp->next) {
strlcat(dlist, ", ", sizecnt);
strlcat(dlist, dp->drivenamep->cname, sizecnt);
}
- ip->drive = Strdup(dlist);
+ ip->drive = dlist;
}
/* Don't continue if we're already hosed */
@@ -406,96 +651,26 @@ main(int argc, char *argv[])
md_exit(sp, 0);
}
- /* Scan qualified disks */
- for (dp = dnlp; dp != NULL; dp = dp->next) {
- mddrivenamelist_t *slp;
-
- /* is the current drive on the skip list? */
- for (slp = skiph; slp != NULL; slp = slp->next) {
- if (dp->drivenamep == slp->drivenamep)
- goto skipdisk;
- }
-
- /*
- * 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,
- * meta_get_set_info returns an ENOTSUP for this disk.
- * Import of partial disksets isn't supported yet,
- * so do NOT put this disk onto any list being set up
- * by metaimport. The partial diskset error message will
- * only be printed once when the first partial diskset is
- * detected. If the user is actually trying to import the
- * partial diskset, print the error and exit; otherwise,
- * print the error and continue.
- */
- if (hasreplica == ENOTSUP) {
- if (report_only) {
- if (!partial) {
- mde_perror(ep, "");
- partial = 1;
- }
- mdclrerror(ep);
- goto skipdisk;
- } else {
- mde_perror(ep, "");
- md_exit(sp, 1);
- }
- }
-
- if (hasreplica < 0) {
- mde_perror(ep, "");
- mdclrerror(ep);
- } else {
- md_im_set_desc_t *p;
- md_im_drive_info_t *d;
-
- rscount += hasreplica;
+ /*
+ * META_IMP_PASS1 means gather the info, but don't report.
+ */
+ (void) process_disks(dnlp, &skiph, pass1_mispp,
+ imp_flags | META_IMP_PASS1, &set_count, overlap, ep);
- /* Eliminate duplicate reporting */
- if (hasreplica > 0) {
- md_timeval32_t firstdisktime;
+ overlap_disks = NULL;
+ overlap = set_disk_overlap(pass1_misp);
+ skiph = NULL;
- /*
- * Go to the tail for the current set
- */
- for (p = misp; p->mis_next != NULL;
- p = p->mis_next);
- firstdisktime =
- p->mis_drives->mid_setcreatetimestamp;
- for (d = p->mis_drives;
- d != NULL;
- d = d->mid_next) {
- /*
- * if the mb_setcreatetime for a disk
- * is not the same as the first disk
- * in the set, don't put it on the
- * skip list. This disk probably
- * doesn't really belong in this set
- * and we'll want to look at it again
- * to figure out where it does belong.
- */
- if ((d->mid_setcreatetimestamp.tv_sec !=
- firstdisktime.tv_sec) ||
- (d->mid_setcreatetimestamp.tv_usec
- != firstdisktime.tv_usec))
- continue;
- skipt =
- meta_drivenamelist_append_wrapper(
- skipt, d->mid_dnp);
- }
- }
- }
-
-skipdisk:
- ;
- }
+ /*
+ * This time call without META_IMP_PASS1 set and we gather
+ * and report the information.
+ * We need to do this twice because of the overlap detection.
+ * The first pass generates a list of disks to detect overlap on.
+ * We then do a second pass using that overlap list to generate
+ * the report.
+ */
+ rscount = process_disks(dnlp, &skiph, mispp, imp_flags, &set_count,
+ overlap, ep);
/*
* Now have entire list of disks associated with diskset including
@@ -508,15 +683,52 @@ skipdisk:
md_im_drive_info_t *d;
mddrivename_t *dnp;
+ if (sp == NULL) {
+ /* Get sp for local set */
+ if ((sp = metasetname(MD_LOCAL_NAME, ep)) == NULL) {
+ mde_perror(ep, "");
+ meta_free_im_set_desc(misp);
+ md_exit(sp, 1);
+ }
+ }
+
for (p = misp; p != NULL; p = p->mis_next) {
for (d = p->mis_drives; d != NULL; d = d->mid_next) {
dnp = d->mid_dnp;
- if (meta_imp_drvused(sp, dnp, ep)) {
- (void) mddserror(ep,
- MDE_DS_DRIVEINUSE, 0, NULL,
- dnp->cname, NULL);
- mde_perror(ep, "");
- md_exit(sp, 0);
+ if (d->mid_available == MD_IM_DISK_AVAILABLE) {
+ if (meta_imp_drvused(sp, dnp, ep)) {
+ (void) mddserror(ep,
+ MDE_DS_DRIVEINUSE, 0, NULL,
+ dnp->cname, NULL);
+ mde_perror(ep, "");
+ meta_free_im_set_desc(misp);
+ md_exit(sp, 1);
+ }
+ } else {
+ /*
+ * If drive is unavailable, then check
+ * that this drive hasn't already been
+ * imported as part of another partial
+ * diskset. Check by devid instead of
+ * cname since the unavailable drive
+ * would have the cname from its
+ * previous system and this may collide
+ * with a valid cname on this system.
+ * Fail if devid is found in another
+ * set or if the routine fails.
+ */
+ mdsetname_t *tmp_sp = NULL;
+
+ if ((meta_is_devid_in_anyset(
+ d->mid_devid, &tmp_sp, ep) == -1) ||
+ (tmp_sp != NULL)) {
+ (void) mddserror(ep,
+ MDE_DS_DRIVEINUSE, 0, NULL,
+ dnp->cname, NULL);
+ mde_perror(ep, "");
+ meta_free_im_set_desc(misp);
+ md_exit(sp, 1);
+ }
}
}
}
@@ -531,9 +743,11 @@ skipdisk:
* If we've found partial disksets but no complete disksets,
* we don't want this to print.
*/
- if (!partial) {
+ if (!misp) {
md_eprintf("%s\n", gettext("no unconfigured sets "
"detected"));
+ meta_free_im_set_desc(misp);
+ md_exit(sp, 1);
}
md_exit(sp, 0);
}
@@ -566,17 +780,15 @@ skipdisk:
gettext("Number of disksets eligible for import"),
set_count);
}
+ }
+ if (overlap) {
+ report_overlap_recommendation();
+ }
- 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 "
- "suggested options for the desired set."));
- }
+ if (have_multiple_sets && !report_only) {
+ md_eprintf("%s\n\n", gettext("multiple unconfigured "
+ "sets detected.\nRerun the command with the "
+ "suggested options for the desired set."));
}
@@ -586,8 +798,29 @@ skipdisk:
*/
if (report_only) {
+ meta_free_im_set_desc(misp);
md_exit(sp, 0);
} else if (have_multiple_sets) {
+ meta_free_im_set_desc(misp);
+ md_exit(sp, 1);
+ } else if (overlap) {
+ md_im_drive_info_t *d;
+ /*
+ * The only way we can get here is if we're doing an import
+ * request on a set that contains at least one disk with
+ * a time conflict. We are prohibiting the importation of
+ * this type of set until the offending disk(s) are turned
+ * off to prevent data corruption.
+ */
+ printf(gettext("To import this set, "));
+ for (d = pass1_misp->mis_drives;
+ d != NULL;
+ d = d->mid_next) {
+ if (d->overlapped_disk)
+ printf("%s ", d->mid_dnp->cname);
+ }
+ printf(gettext("must be removed from the system\n"));
+ meta_free_im_set_desc(misp);
md_exit(sp, 1);
}
@@ -595,32 +828,50 @@ skipdisk:
usage(sp, gettext("You must specify a new set name."));
}
+ /*
+ * The user must specify the -f (force) flag if the following
+ * conditions exist:
+ * - partial diskset
+ * - stale diskset
+ */
+ if (meta_replica_quorum(misp) != 0)
+ no_quorum = 1;
+ if (misp->mis_partial || no_quorum) {
+ if (!force)
+ usage(sp, gettext("You must specify the force flag"));
+ }
(void) meta_imp_set(misp, setname_new, force, dry_run, ep);
-
if (dry_run) {
+ meta_free_im_set_desc(misp);
md_exit(sp, 0);
}
if (!mdisok(ep)) {
+ meta_free_im_set_desc(misp);
mde_perror(ep, "");
md_exit(sp, 1);
}
if ((sp = metasetname(setname_new, ep)) == NULL) {
+ meta_free_im_set_desc(misp);
mde_perror(ep, "");
md_exit(sp, 1);
}
if (meta_lock_nowait(sp, ep) != 0) {
+ meta_free_im_set_desc(misp);
mde_perror(ep, "");
md_exit(sp, 10); /* special errcode */
}
- if (meta_set_take(sp, &mhiargs, 0, 0, &status)) {
+ if (meta_set_take(sp, &mhiargs, (misp->mis_partial | TAKE_IMP),
+ 0, &status)) {
+ meta_free_im_set_desc(misp);
mde_perror(&status, "");
md_exit(sp, 1);
}
+ meta_free_im_set_desc(misp);
md_exit(sp, 0);
/*NOTREACHED*/
return (0);
diff --git a/usr/src/cmd/lvm/util/metaset.c b/usr/src/cmd/lvm/util/metaset.c
index 59c803d2f3..953554e3c5 100644
--- a/usr/src/cmd/lvm/util/metaset.c
+++ b/usr/src/cmd/lvm/util/metaset.c
@@ -1510,6 +1510,7 @@ parse_takeset(int argc, char **argv)
sdssc_boolean_e cluster_take = SDSSC_False;
sdssc_version_t vers;
rval_e rval;
+ int set_take_rval;
/* reset and parse args */
optind = 1;
@@ -1646,7 +1647,30 @@ parse_takeset(int argc, char **argv)
md_exit(sp, 10); /* special errcode */
}
- if (meta_set_take(sp, &mhiargs, flags, usetag, &status)) {
+ /*
+ * If a 2 is returned from meta_set_take, this take was able to resolve
+ * an unresolved replicated disk (i.e. a disk is now available that
+ * had been missing during the import of the replicated diskset).
+ * Need to release the diskset and re-take in order to have
+ * the subdrivers re-snarf using the newly resolved (or newly mapped)
+ * devids. This also allows the namespace to be updated with the
+ * correct major names in the case where the disk being replicated
+ * was handled by a different driver than the replicated disk.
+ */
+ set_take_rval = meta_set_take(sp, &mhiargs, flags, usetag, &status);
+ if (set_take_rval == 2) {
+ if (meta_set_release(sp, &status)) {
+ mde_perror(&status,
+ "Need to release and take set to resolve names.");
+ md_exit(sp, 1);
+ }
+ metaflushdrivenames();
+ metaflushsetname(sp);
+ set_take_rval = meta_set_take(sp, &mhiargs,
+ (flags | TAKE_RETAKE), usetag, &status);
+ }
+
+ if (set_take_rval == -1) {
mde_perror(&status, "");
if (mdismddberror(&status, MDE_DB_TAGDATA))
md_exit(sp, 2);