2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright (c) 1995, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Metadevice diskset interfaces
2N/A */
2N/A
2N/A#include "meta_set_prv.h"
2N/A#include "meta_runtime.h"
2N/A#include <meta.h>
2N/A#include <sys/lvm/md_mddb.h>
2N/A#include <sys/cladm.h>
2N/A#include <devid.h>
2N/A#include <sys/lvm/md_convert.h>
2N/A#include <sys/lvm/mdvar.h>
2N/A#include <sdssc.h>
2N/A
2N/A/*
2N/A * meta_devid_supported_in_did()
2N/A *
2N/A * Used to see if the Sun Cluster did driver supports
2N/A * device ids.
2N/A *
2N/A * Returns MD_DEVID_SUPPORTED if supported
2N/A * MD_DEVID_NOT_SUPPORTED if not supported
2N/A */
2N/Aint
2N/Ameta_devid_supported_in_did(void)
2N/A{
2N/A static int idevid = MD_DEVID_NO_INIT;
2N/A md_error_t mderr;
2N/A
2N/A /*
2N/A * We only want to make the expensive ioctl when needed
2N/A */
2N/A if (idevid != MD_DEVID_NO_INIT)
2N/A return (idevid);
2N/A
2N/A mderr.host = NULL;
2N/A mderr.extra = NULL;
2N/A mderr.name = NULL;
2N/A if (metaioctl(MD_DID_DEVID, &idevid, &mderr, NULL) != 0)
2N/A idevid = MD_DEVID_NOT_SUPPORTED;
2N/A
2N/A return (idevid);
2N/A}
2N/A
2N/A/*
2N/A * Exported Entry Points
2N/A */
2N/A
2N/Aint
2N/Acheckdrive_onnode(
2N/A mdsetname_t *sp,
2N/A mddrivename_t *dnp,
2N/A char *node,
2N/A md_error_t *ep)
2N/A{
2N/A time_t mystamp, otherstamp;
2N/A md_dev64_t otherdev;
2N/A mdname_t *np, *remote_np;
2N/A mddrivename_t *remote_dnp;
2N/A int release = 0;
2N/A md_drive_desc dd;
2N/A int rval = 0;
2N/A int ret = -1;
2N/A mhd_mhiargs_t mhiargs;
2N/A md_set_desc *sd;
2N/A int is_efi = 0;
2N/A int do_fallback = 0;
2N/A char *p;
2N/A
2N/A (void) memset(&mhiargs, '\0', sizeof (mhiargs));
2N/A
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (meta_is_drive_in_thisset(sp, dnp, FALSE, ep)) {
2N/A release = 1;
2N/A dd.dd_next = NULL;
2N/A dd.dd_dbcnt = 0;
2N/A dd.dd_dbsize = 0;
2N/A dd.dd_dnp = dnp;
2N/A if (clnt_gtimeout(mynode(), sp, &mhiargs, ep) != 0)
2N/A return (-1);
2N/A if (!(MD_MNSET_DESC(sd)) && !MD_ATSET_DESC(sd)) {
2N/A if (rel_own_bydd(sp, &dd, TRUE, ep))
2N/A return (-1);
2N/A }
2N/A }
2N/A if ((np = metaslicename(dnp, MD_SLICE0, ep)) == NULL) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * First try and operate assuming the other side
2N/A * is running a SVM version that supports device id
2N/A * in disksets i.e. is running SVM RPC version 2.
2N/A *
2N/A * If this call fails due to the other side running
2N/A * a SVM version that does not support device id
2N/A * in disksets i.e. is running SVM RPC version 1, we
2N/A * fallback to the old behaviour.
2N/A */
2N/A if (dnp->devid != NULL && disk_do_devid_check() == B_TRUE) {
2N/A char *rname = NULL;
2N/A md_dev64_t dev = NODEV64;
2N/A ddi_devid_t rdevid = NULL;
2N/A char *rminor = NULL;
2N/A char *devidstr = NULL;
2N/A
2N/A /*
2N/A * If the disk is connected to the remote node then the
2N/A * only thing we can be certain of is that the disk will
2N/A * have the same devid on that node, it may not have the
2N/A * same minor number nor the same ctd name. But if it
2N/A * does have the same ctd name then use it. In most cases
2N/A * there will only be a single entry returned but if the
2N/A * system has multi-path disks with MPXIO turned off there
2N/A * will be multiple entries. Attempting to choose the same
2N/A * name will give the user as consistent a view across the
2N/A * nodes as possible.
2N/A */
2N/A if (devid_str_decode(dnp->devid, &rdevid, NULL) == -1) {
2N/A do_fallback++;
2N/A goto fallback;
2N/A }
2N/A
2N/A if ((rminor = meta_getminor_name(np->rname, ep)) != NULL) {
2N/A if ((devidstr = devid_str_encode(rdevid,
2N/A rminor)) == NULL) {
2N/A Free(rminor);
2N/A devid_free(rdevid);
2N/A do_fallback++;
2N/A goto fallback;
2N/A }
2N/A
2N/A /*
2N/A * we have a valid devid and minor name.
2N/A */
2N/A if (((p = getenv("MD_DEBUG")) != NULL) &&
2N/A (strstr(p, "DEVID") != NULL)) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "searching for %s on %s\n"),
2N/A devidstr, node);
2N/A }
2N/A
2N/A ret = clnt_devinfo_by_devid(node, sp, devidstr, &dev,
2N/A np->rname, &rname, NULL, ep);
2N/A
2N/A devid_str_free(devidstr);
2N/A Free(rminor);
2N/A } else {
2N/A /*
2N/A * Unable to get a minor name for the device so try
2N/A * searching without one which is painfully slow.
2N/A */
2N/A if (((p = getenv("MD_DEBUG")) != NULL) &&
2N/A (strstr(p, "DEVID") != NULL)) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "searching for %s on %s\n"),
2N/A dnp->devid, node);
2N/A }
2N/A
2N/A ret = clnt_devinfo_by_devid(node, sp, dnp->devid, &dev,
2N/A np->rname, &rname, NULL, ep);
2N/A }
2N/A
2N/A devid_free(rdevid);
2N/A
2N/A /*
2N/A * If the return value was ENOTSUP, we know the
2N/A * other side is not running a SVM version that
2N/A * supports device id in disksets. We fallback
2N/A * to the previous behaviour in that case.
2N/A */
2N/A if (ret == ENOTSUP) {
2N/A do_fallback++;
2N/A goto fallback;
2N/A } else if (ret == -1) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * If the device does not exist on the remote node then
2N/A * the returned dev should indicate this (NODEV64) but
2N/A * we also check to make sure the returned name is not
2N/A * empty to make sure that the namespace does not get
2N/A * created with a NULL/empty entry (should not be possbile
2N/A * but being paranoid).
2N/A */
2N/A if (dev == NODEV64 || rname == (char *)NULL ||
2N/A strcmp(rname, "") == 0) {
2N/A rval = mddserror(ep, MDE_DS_DRIVENOTCOMMON, sp->setno,
2N/A node, dnp->cname, sp->setname);
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * The rname returned from the remote node maybe different
2N/A * to the rname on this node, therefore we need to build up
2N/A * a dnp for this new rname.
2N/A */
2N/A if (strcmp(np->rname, rname) != 0) {
2N/A /* different rname */
2N/A remote_np = metaname_fast(&sp, rname,
2N/A LOGICAL_DEVICE, ep);
2N/A if (remote_np != NULL) {
2N/A remote_dnp = remote_np->drivenamep;
2N/A }
2N/A } else {
2N/A remote_dnp = dnp;
2N/A }
2N/A } else {
2N/A do_fallback++;
2N/A }
2N/A
2N/Afallback:
2N/A if (do_fallback) {
2N/A if (((p = getenv("MD_DEBUG")) != NULL) &&
2N/A (strstr(p, "DEVID") != NULL)) {
2N/A (void) fprintf(stderr, dgettext(TEXT_DOMAIN,
2N/A "failback search for %s on %s\n"),
2N/A dnp->rname, node);
2N/A }
2N/A
2N/A ret = setdevstamp(dnp, &mystamp, ep);
2N/A /*
2N/A * Check if the disk in question is an EFI disk.
2N/A */
2N/A if (ret == ENOTSUP)
2N/A is_efi++;
2N/A else if (ret == -1)
2N/A return (-1);
2N/A
2N/A if ((np = metaslicename(dnp, MD_SLICE0, ep)) == NULL) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A if (is_efi) {
2N/A /*
2N/A * For EFI disks, we compare the device
2N/A * id for the disks in question.
2N/A */
2N/A ddi_devid_t thisdevid, otherdevid;
2N/A char *encoded_otherdevid = NULL;
2N/A char *encoded_thisdevid = NULL;
2N/A
2N/A if (clnt_devinfo(node, sp, dnp, &otherdev, NULL, ep)
2N/A == -1) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A if (np->dev != otherdev) {
2N/A rval = mddserror(ep, MDE_DS_DRIVENOTCOMMON,
2N/A sp->setno, node, dnp->cname, sp->setname);
2N/A goto out;
2N/A }
2N/A
2N/A if (clnt_devid(node, sp, dnp, &encoded_otherdevid,
2N/A ep) == -1) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A if (encoded_otherdevid == NULL) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A if (devid_str_decode(encoded_otherdevid, &otherdevid,
2N/A NULL) == 0) {
2N/A /*
2N/A * If we are here, it means that dnp->devid
2N/A * is NULL.
2N/A *
2N/A * We want to explicitly get the device id
2N/A * for such a disk
2N/A */
2N/A encoded_thisdevid = meta_get_devid(dnp->rname);
2N/A ret = devid_str_decode(encoded_thisdevid,
2N/A &thisdevid, NULL);
2N/A if (ret == 0) {
2N/A ret = devid_compare(thisdevid,
2N/A otherdevid);
2N/A devid_free(thisdevid);
2N/A }
2N/A devid_free(otherdevid);
2N/A if (encoded_thisdevid)
2N/A Free(encoded_thisdevid);
2N/A }
2N/A
2N/A Free(encoded_otherdevid);
2N/A if (ret != 0) {
2N/A rval = mddserror(ep, MDE_DS_DRIVENOTCOMMON,
2N/A sp->setno, node, dnp->cname, sp->setname);
2N/A goto out;
2N/A }
2N/A } else {
2N/A /*
2N/A * For VTOC disks, we compare the dev_t and
2N/A * timestamp for the disks in question.
2N/A */
2N/A if (clnt_devinfo(node, sp, dnp, &otherdev,
2N/A &otherstamp, ep) == -1) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A if ((mystamp != otherstamp) || (np->dev != otherdev)) {
2N/A rval = mddserror(ep, MDE_DS_DRIVENOTCOMMON,
2N/A sp->setno, node, dnp->cname, sp->setname);
2N/A goto out;
2N/A }
2N/A }
2N/A remote_dnp = dnp;
2N/A }
2N/A
2N/A if (((p = getenv("MD_DEBUG")) != NULL) &&
2N/A (strstr(p, "DEVID") != NULL))
2N/A (void) fprintf(stderr,
2N/A dgettext(TEXT_DOMAIN, "found %s on node %s\n"),
2N/A remote_dnp->rname, node);
2N/A
2N/A if (clnt_drvused(node, sp, remote_dnp, ep) == -1)
2N/A rval = -1;
2N/A
2N/Aout:
2N/A if (release)
2N/A if (!(MD_MNSET_DESC(sd)) && !MD_ATSET_DESC(sd)) {
2N/A if (tk_own_bydd(sp, &dd, &mhiargs, TRUE, ep))
2N/A rval = -1;
2N/A }
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/Aside_t
2N/Agetnodeside(char *node, md_set_desc *sd)
2N/A{
2N/A side_t sideno;
2N/A int nid;
2N/A md_mnnode_desc *nd;
2N/A
2N/A if (MD_MNSET_DESC(sd)) {
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A if (strcmp(nd->nd_nodename, node) == 0) {
2N/A return (nd->nd_nodeid);
2N/A }
2N/A nd = nd->nd_next;
2N/A }
2N/A return (MD_SIDEWILD);
2N/A }
2N/A
2N/A
2N/A /* If regular diskset */
2N/A for (sideno = 0; sideno < MD_MAXSIDES; sideno++) {
2N/A if (sd->sd_nodes[sideno] == NULL ||
2N/A sd->sd_nodes[sideno][0] == '\0')
2N/A continue;
2N/A
2N/A if (strcmp(sd->sd_nodes[sideno], node) == 0) {
2N/A return (sideno);
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If the first loop fails we may be in a situation where this host
2N/A * is configured as part of a cluster yet not running in the cluster
2N/A * mode. If so, the names stored in sd->sd_nodes[] are going to be
2N/A * nodeid's instead of hostnames. See if we can find a match that way.
2N/A */
2N/A if (_cladm(CL_CONFIG, CL_NODEID, &nid) == 0) {
2N/A for (sideno = 0; sideno < MD_MAXSIDES; sideno++) {
2N/A if (sd->sd_nodes[sideno] == NULL ||
2N/A sd->sd_nodes[sideno][0] == '\0')
2N/A continue;
2N/A if (atoi(sd->sd_nodes[sideno]) == nid)
2N/A return (sideno);
2N/A }
2N/A }
2N/A
2N/A return (MD_SIDEWILD);
2N/A}
2N/A
2N/Aint
2N/Ahalt_set(mdsetname_t *sp, md_error_t *ep)
2N/A{
2N/A mddb_config_t c;
2N/A
2N/A (void) memset(&c, 0, sizeof (c));
2N/A c.c_setno = sp->setno;
2N/A if ((c.c_sideno = getmyside(sp, ep)) == MD_SIDEWILD)
2N/A return (-1);
2N/A
2N/A if (s_ownset(sp->setno, ep) == MD_SETOWNER_YES) {
2N/A /* Don't need device id information from this ioctl */
2N/A c.c_locator.l_devid = (uint64_t)0;
2N/A c.c_locator.l_devid_flags = 0;
2N/A /* Kill any resyncs that are running on mirrors in this set */
2N/A meta_mirror_resync_kill(sp);
2N/A if (metaioctl(MD_RELEASE_SET, &c, &c.c_mde, NULL) != 0)
2N/A return (mdstealerror(ep, &c.c_mde));
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Amd_drive_desc *
2N/Ametadrivedesc_append(
2N/A md_drive_desc **dd,
2N/A mddrivename_t *dnp,
2N/A int dbcnt,
2N/A int dbsize,
2N/A md_timeval32_t timestamp,
2N/A ulong_t genid,
2N/A uint_t flags
2N/A)
2N/A{
2N/A md_drive_desc *p;
2N/A
2N/A /* run to end of list */
2N/A for (/* void */; (*dd != NULL); dd = &(*dd)->dd_next)
2N/A /* void */;
2N/A
2N/A /* allocate new list element */
2N/A p = *dd = Zalloc(sizeof (*p));
2N/A
2N/A p->dd_dnp = dnp;
2N/A p->dd_dbcnt = dbcnt;
2N/A p->dd_dbsize = dbsize;
2N/A p->dd_ctime = timestamp;
2N/A p->dd_genid = genid;
2N/A p->dd_flags = flags;
2N/A return (p);
2N/A}
2N/A
2N/Aint
2N/Anodehasset(
2N/A mdsetname_t *sp,
2N/A char *node,
2N/A uint_t match_flag,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_set_desc *sd;
2N/A md_set_record *sr;
2N/A int rval = 0;
2N/A
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* Don't care if set record is MN or not */
2N/A if (clnt_getset(node, sp->setname, MD_SET_BAD, &sr, ep))
2N/A return (-1);
2N/A
2N/A if (sr == NULL) {
2N/A if (! mdisok(ep))
2N/A return (-1);
2N/A return (0);
2N/A }
2N/A
2N/A /* Looking for name only match */
2N/A if ((match_flag & NHS_N_EQ) == NHS_N_EQ) {
2N/A rval = 1;
2N/A goto out;
2N/A }
2N/A
2N/A if (sd->sd_setno != sr->sr_setno)
2N/A goto out;
2N/A
2N/A /* Looking for name and setno match */
2N/A if ((match_flag & NHS_NS_EQ) == NHS_NS_EQ) {
2N/A rval = 1;
2N/A goto out;
2N/A }
2N/A
2N/A if (sd->sd_ctime.tv_sec != sr->sr_ctime.tv_sec ||
2N/A sd->sd_ctime.tv_usec != sr->sr_ctime.tv_usec)
2N/A goto out;
2N/A
2N/A /* Looking for name, setno, and timestamp match */
2N/A if ((match_flag & NHS_NST_EQ) == NHS_NST_EQ) {
2N/A rval = 1;
2N/A goto out;
2N/A }
2N/A
2N/A if (sd->sd_genid != sr->sr_genid) {
2N/A if (sd->sd_genid < sr->sr_genid) {
2N/A /*
2N/A * Looking for name, setno, timestamp, and genid on
2N/A * other host is GT than other host.
2N/A */
2N/A if ((match_flag & NHS_NST_EQ_G_GT) == NHS_NST_EQ_G_GT) {
2N/A rval = 1;
2N/A goto out;
2N/A }
2N/A }
2N/A goto out;
2N/A }
2N/A
2N/A /* Looking for name, setno, timestamp, and genid match */
2N/A if ((match_flag & NHS_NSTG_EQ) == NHS_NSTG_EQ)
2N/A rval = 1;
2N/A
2N/Aout:
2N/A /*
2N/A * Set record structure was allocated from RPC routine getset
2N/A * so this structure is only of size md_set_record even if
2N/A * the MN flag is set. So, clear the flag so that the free
2N/A * code doesn't attempt to free a structure the size of
2N/A * md_mnset_record.
2N/A */
2N/A sr->sr_flags &= ~MD_SR_MN;
2N/A free_sr(sr);
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/Aint
2N/Anodesuniq(mdsetname_t *sp, int cnt, char **strings, md_error_t *ep)
2N/A{
2N/A int i, j;
2N/A for (i = 0; i < cnt; i++)
2N/A for (j = i + 1; j < cnt; j++)
2N/A if (strcmp(strings[i], strings[j]) == 0)
2N/A return (mddserror(ep, MDE_DS_DUPHOST,
2N/A sp->setno, strings[i], NULL, sp->setname));
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Aown_set(mdsetname_t *sp, char **owner_of_set, int forceflg, md_error_t *ep)
2N/A{
2N/A md_set_desc *sd;
2N/A int am_i_owner;
2N/A int i;
2N/A
2N/A if (metaislocalset(sp)) {
2N/A if (owner_of_set != NULL)
2N/A *owner_of_set = Strdup(mynode());
2N/A return (MD_SETOWNER_YES);
2N/A }
2N/A
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (clnt_ownset(mynode(), sp, &am_i_owner, ep) == -1)
2N/A return (-1);
2N/A
2N/A if (MD_MNSET_DESC(sd)) {
2N/A if (am_i_owner == TRUE)
2N/A return (MD_SETOWNER_YES);
2N/A else
2N/A return (MD_SETOWNER_NO);
2N/A }
2N/A
2N/A if (forceflg == TRUE) {
2N/A if (am_i_owner == TRUE) {
2N/A if (owner_of_set != NULL)
2N/A *owner_of_set = Strdup(mynode());
2N/A return (MD_SETOWNER_YES);
2N/A }
2N/A
2N/A if (owner_of_set != NULL)
2N/A *owner_of_set = NULL;
2N/A return (MD_SETOWNER_NONE);
2N/A }
2N/A
2N/A if (am_i_owner == TRUE) {
2N/A if (owner_of_set != NULL)
2N/A *owner_of_set = Strdup(mynode());
2N/A return (MD_SETOWNER_YES);
2N/A }
2N/A
2N/A
2N/A for (i = 0; i < MD_MAXSIDES; i++) {
2N/A /*
2N/A * Skip empty slots, and my own slot.
2N/A */
2N/A if (sd->sd_nodes[i][0] == '\0' ||
2N/A strcmp(sd->sd_nodes[i], mynode()) == 0)
2N/A continue;
2N/A
2N/A if (clnt_ownset(sd->sd_nodes[i], sp, &am_i_owner, ep) == -1)
2N/A return (-1);
2N/A
2N/A if (am_i_owner == TRUE) {
2N/A if (owner_of_set != NULL)
2N/A *owner_of_set = Strdup(sd->sd_nodes[i]);
2N/A return (MD_SETOWNER_NO);
2N/A }
2N/A }
2N/A
2N/A /* We get here, we currently have no owner. */
2N/A if (owner_of_set != NULL)
2N/A *owner_of_set = NULL;
2N/A return (MD_SETOWNER_NONE);
2N/A}
2N/A
2N/Avoid
2N/Aresync_genid(
2N/A mdsetname_t *sp,
2N/A md_set_desc *sd,
2N/A ulong_t max_genid,
2N/A int node_c,
2N/A char **node_v
2N/A)
2N/A{
2N/A int i, j;
2N/A ulong_t cur_genid[MD_MAXSIDES];
2N/A md_set_record *sr;
2N/A md_error_t xep = mdnullerror;
2N/A md_mnnode_desc *nd;
2N/A md_mnset_record *mnsr;
2N/A
2N/A if (node_c > 0 && node_v && *node_v) {
2N/A /*
2N/A * Mark the set record MD_SR_OK.
2N/A */
2N/A for (i = 0; i < node_c; i++)
2N/A if (clnt_upd_sr_flags(node_v[i], sp, MD_SR_OK, &xep))
2N/A mdclrerror(&xep);
2N/A max_genid++;
2N/A }
2N/A
2N/A if (MD_MNSET_DESC(sd)) {
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A /* Will only return a multi-node diskset record */
2N/A if (clnt_mngetset(nd->nd_nodename, sp->setname,
2N/A MD_SET_BAD, &mnsr, &xep) == -1) {
2N/A mdclrerror(&xep);
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A for (j = mnsr->sr_genid; j < max_genid; j++) {
2N/A if (clnt_upd_sr_flags(nd->nd_nodename, sp,
2N/A MD_SR_OK, &xep))
2N/A mdclrerror(&xep);
2N/A }
2N/A free_sr((struct md_set_record *)mnsr);
2N/A nd = nd->nd_next;
2N/A }
2N/A return;
2N/A }
2N/A
2N/A /*
2N/A * Get current genid for each node.
2N/A */
2N/A for (i = 0; i < MD_MAXSIDES; i++) {
2N/A cur_genid[i] = 0;
2N/A
2N/A /* Skip empty slots */
2N/A if (sd->sd_nodes[i][0] == '\0')
2N/A continue;
2N/A
2N/A /* Should be a non-multinode diskset */
2N/A if (clnt_getset(sd->sd_nodes[i], sp->setname,
2N/A MD_SET_BAD, &sr, &xep) == -1) {
2N/A mdclrerror(&xep);
2N/A continue;
2N/A }
2N/A
2N/A if (MD_MNSET_REC(sr)) {
2N/A /*
2N/A * Set record structure was allocated from RPC routine
2N/A * getset so this structure is only of size
2N/A * md_set_record even if the MN flag is set. So,
2N/A * clear the flag so that the free code doesn't
2N/A * attempt to free a structure the size of
2N/A * md_mnset_record.
2N/A */
2N/A sr->sr_flags &= ~MD_SR_MN;
2N/A free_sr(sr);
2N/A continue;
2N/A }
2N/A
2N/A cur_genid[i] = sr->sr_genid;
2N/A
2N/A free_sr(sr);
2N/A }
2N/A
2N/A /*
2N/A * Mark the set record MD_SR_OK
2N/A */
2N/A for (i = 0; i < MD_MAXSIDES; i++) {
2N/A /* Skip empty slots */
2N/A if (sd->sd_nodes[i][0] == '\0')
2N/A continue;
2N/A
2N/A for (j = cur_genid[i]; j < max_genid; j++)
2N/A if (clnt_upd_sr_flags(sd->sd_nodes[i], sp, MD_SR_OK,
2N/A &xep))
2N/A mdclrerror(&xep);
2N/A
2N/A }
2N/A}
2N/A
2N/Aint
2N/Asetup_db_bydd(mdsetname_t *sp, md_drive_desc *dd, int force, md_error_t *ep)
2N/A{
2N/A md_drive_desc *p;
2N/A struct mddb_config c;
2N/A int i, clboot = 0;
2N/A md_set_desc *sd;
2N/A int use_devid = 1;
2N/A ddi_devid_t devidp, new_devidp;
2N/A char *minor_name = NULL;
2N/A size_t sz;
2N/A char *devid_str = NULL;
2N/A int need_to_free_devidp = 0;
2N/A
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if (_cladm(CL_INITIALIZE, CL_GET_BOOTFLAG, &clboot) != 0) {
2N/A return (-1);
2N/A }
2N/A
2N/A (void) memset(&c, 0, sizeof (c));
2N/A
2N/A c.c_setno = sp->setno;
2N/A (void) strcpy(c.c_setname, sp->setname);
2N/A if ((c.c_sideno = getmyside(sp, ep)) == MD_SIDEWILD)
2N/A return (-1);
2N/A
2N/A c.c_timestamp = sd->sd_ctime;
2N/A
2N/A if (setup_med_cfg(sp, &c, force, ep))
2N/A return (-1);
2N/A
2N/A for (p = dd; p != NULL; p = p->dd_next) {
2N/A mddrivename_t *dnp;
2N/A mdname_t *np;
2N/A mdcinfo_t *cinfo;
2N/A mdsidenames_t *sn = NULL;
2N/A
2N/A if (p->dd_dbcnt == 0)
2N/A continue;
2N/A
2N/A dnp = p->dd_dnp;
2N/A
2N/A assert(dnp != NULL);
2N/A
2N/A for (sn = dnp->side_names; sn != NULL; sn = sn->next) {
2N/A if (sn->sideno == c.c_sideno)
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * The disk has no side name information
2N/A */
2N/A if (sn == NULL) {
2N/A uint_t rep_slice;
2N/A
2N/A if ((meta_replicaslice(dnp, &rep_slice, ep) != 0) ||
2N/A ((np = metaslicename(dnp, rep_slice, ep))
2N/A == NULL)) {
2N/A mdclrerror(ep);
2N/A continue;
2N/A }
2N/A
2N/A if (np->dev == NODEV64)
2N/A continue;
2N/A
2N/A c.c_locator.l_dev = meta_cmpldev(np->dev);
2N/A c.c_locator.l_mnum = meta_getminor(np->dev);
2N/A
2N/A /*
2N/A * minor_name will be NULL if dnp->devid == NULL
2N/A * - see metagetvtoc()
2N/A */
2N/A if (np->minor_name != NULL)
2N/A minor_name = Strdup(np->minor_name);
2N/A
2N/A if ((cinfo = metagetcinfo(np, ep)) == NULL) {
2N/A mdclrerror(ep);
2N/A continue;
2N/A }
2N/A
2N/A (void) strncpy(c.c_locator.l_driver, cinfo->dname,
2N/A sizeof (c.c_locator.l_driver));
2N/A } else {
2N/A c.c_locator.l_dev = NODEV32;
2N/A c.c_locator.l_mnum = sn->mnum;
2N/A (void) strncpy(c.c_locator.l_driver, sn->dname,
2N/A sizeof (c.c_locator.l_driver));
2N/A
2N/A if (dnp->devid != NULL) {
2N/A if (MD_MNSET_DESC(sd)) {
2N/A minor_name = meta_getdidminorbykey(
2N/A MD_LOCAL_SET, sn->sideno,
2N/A dnp->side_names_key, ep);
2N/A } else {
2N/A minor_name = meta_getdidminorbykey(
2N/A MD_LOCAL_SET, sn->sideno + SKEW,
2N/A dnp->side_names_key, ep);
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If the device does not have a devid or
2N/A * did driver does not support devids.
2N/A */
2N/A if (dnp->devid == NULL || meta_devid_supported_in_did()
2N/A == MD_DEVID_NOT_SUPPORTED)
2N/A use_devid = 0;
2N/A
2N/A if (use_devid) {
2N/A /*
2N/A * The devid associated with the dnp does not have
2N/A * a minor name and so we must add it in.
2N/A */
2N/A size_t len = strlen(dnp->devid) +
2N/A strlen(minor_name) + 2;
2N/A devid_str = (char *)Malloc(len);
2N/A (void) snprintf(devid_str, len, "%s/%s", dnp->devid,
2N/A minor_name);
2N/A (void) devid_str_decode(devid_str, &devidp, NULL);
2N/A need_to_free_devidp = 1;
2N/A
2N/A /* If need to fix LB then setup old_devid info */
2N/A if (p->dd_flags & MD_DR_FIX_LB_NM_DID) {
2N/A sz = devid_sizeof(devidp);
2N/A c.c_locator.l_old_devid_sz = sz;
2N/A c.c_locator.l_old_devid = (uintptr_t)malloc(sz);
2N/A (void) memcpy((void *)(uintptr_t)
2N/A c.c_locator.l_old_devid,
2N/A devidp, sz);
2N/A
2N/A new_devidp = replicated_list_lookup(
2N/A devid_sizeof((ddi_devid_t)devidp),
2N/A (void *)(uintptr_t)devidp);
2N/A devid_free(devidp);
2N/A need_to_free_devidp = 0;
2N/A devidp = new_devidp;
2N/A
2N/A }
2N/A sz = devid_sizeof(devidp);
2N/A c.c_locator.l_devid = (uintptr_t)malloc(sz);
2N/A c.c_locator.l_devid_sz = sz;
2N/A (void) memcpy((void *)(uintptr_t)
2N/A c.c_locator.l_devid,
2N/A devidp, sz);
2N/A if (need_to_free_devidp) {
2N/A devid_free(devidp);
2N/A need_to_free_devidp = 0;
2N/A }
2N/A if (minor_name == NULL) {
2N/A /* ERROR fix up */
2N/A Free(devid_str);
2N/A Free((void *)(uintptr_t)c.c_locator.l_devid);
2N/A if (c.c_locator.l_old_devid_sz) {
2N/A Free((void *)
2N/A (uintptr_t)c.c_locator.l_old_devid);
2N/A c.c_locator.l_old_devid_sz = 0;
2N/A c.c_locator.l_old_devid =
2N/A (uintptr_t)NULL;
2N/A }
2N/A return (-1);
2N/A }
2N/A (void) strcpy(c.c_locator.l_minor_name,
2N/A minor_name);
2N/A c.c_locator.l_devid_flags = MDDB_DEVID_VALID |
2N/A MDDB_DEVID_SPACE | MDDB_DEVID_SZ;
2N/A } else {
2N/A /*
2N/A * Don't need device id information from
2N/A * this ioctl
2N/A */
2N/A c.c_locator.l_devid = (uint64_t)0;
2N/A c.c_locator.l_devid_flags = 0;
2N/A }
2N/A
2N/A for (i = 0; i < p->dd_dbcnt; i++) {
2N/A c.c_locator.l_flags = 0;
2N/A c.c_locator.l_blkno = 16 + i * p->dd_dbsize;
2N/A
2N/A if (metaioctl(MD_DB_USEDEV, &c, &c.c_mde, NULL) != 0) {
2N/A if (use_devid) {
2N/A Free(devid_str);
2N/A Free((void *)
2N/A (uintptr_t)c.c_locator.l_devid);
2N/A if (c.c_locator.l_old_devid_sz) {
2N/A Free((void *)(uintptr_t)
2N/A c.c_locator.l_old_devid);
2N/A c.c_locator.l_old_devid_sz = 0;
2N/A c.c_locator.l_old_devid =
2N/A (uintptr_t)NULL;
2N/A }
2N/A }
2N/A Free(minor_name);
2N/A return (mdstealerror(ep, &c.c_mde));
2N/A }
2N/A }
2N/A if (use_devid) {
2N/A Free(devid_str);
2N/A Free((void *)(uintptr_t)c.c_locator.l_devid);
2N/A if (c.c_locator.l_old_devid_sz) {
2N/A Free((void *)
2N/A (uintptr_t)c.c_locator.l_old_devid);
2N/A c.c_locator.l_old_devid_sz = 0;
2N/A c.c_locator.l_old_devid = (uintptr_t)NULL;
2N/A }
2N/A }
2N/A Free(minor_name);
2N/A }
2N/A
2N/A /* return success */
2N/A return (0);
2N/A}
2N/A
2N/Aint
2N/Asnarf_set(mdsetname_t *sp, bool_t stale_bool, md_error_t *ep)
2N/A{
2N/A mddb_config_t c;
2N/A
2N/A (void) memset(&c, '\0', sizeof (c));
2N/A
2N/A c.c_setno = sp->setno;
2N/A if ((c.c_sideno = getmyside(sp, ep)) == MD_SIDEWILD)
2N/A return (-1);
2N/A
2N/A /* Don't need device id information from this ioctl */
2N/A c.c_locator.l_devid = (uint64_t)0;
2N/A c.c_locator.l_devid_flags = 0;
2N/A if (stale_bool == TRUE) {
2N/A c.c_flags = MDDB_C_STALE;
2N/A }
2N/A if (metaioctl(MD_GRAB_SET, &c, &c.c_mde, NULL) != 0)
2N/A return (mdstealerror(ep, &c.c_mde));
2N/A
2N/A if (c.c_flags & MDDB_C_STALE)
2N/A return (mdmddberror(ep, MDE_DB_STALE, (minor_t)NODEV64,
2N/A sp->setno, 0, NULL));
2N/A
2N/A return (0);
2N/A}