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/*
2N/A * Metadevice diskset interfaces
2N/A */
2N/A
2N/A#include "meta_set_prv.h"
2N/A#include <sys/lvm/md_crc.h>
2N/A#include <strings.h>
2N/A#include <sys/bitmap.h>
2N/A
2N/Aextern char *blkname(char *);
2N/A
2N/Astatic int
2N/Aupd_dr_dbinfo(
2N/A mdsetname_t *sp,
2N/A md_set_desc *sd,
2N/A md_drive_desc *dd,
2N/A md_replicalist_t *rlp,
2N/A int forceflg,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_drive_desc *p;
2N/A md_replica_t *r;
2N/A md_replicalist_t *rl;
2N/A int i;
2N/A int dbcnt;
2N/A int rval = 0;
2N/A daddr_t nblks = 0;
2N/A md_setkey_t *cl_sk;
2N/A md_error_t xep = mdnullerror;
2N/A md_mnnode_desc *nd;
2N/A ddi_devid_t devid;
2N/A
2N/A /* find the smallest existing replica */
2N/A for (rl = rlp; rl != NULL; rl = rl->rl_next) {
2N/A r = rl->rl_repp;
2N/A nblks = ((nblks == 0) ? r->r_nblk : min(r->r_nblk, nblks));
2N/A }
2N/A
2N/A if (nblks <= 0)
2N/A nblks = (MD_MNSET_DESC(sd)) ? MD_MN_DBSIZE : MD_DBSIZE;
2N/A
2N/A for (p = dd; p != NULL; p = p->dd_next) {
2N/A dbcnt = 0;
2N/A for (rl = rlp; rl != NULL; rl = rl->rl_next) {
2N/A r = rl->rl_repp;
2N/A
2N/A /*
2N/A * Before we bump up the dbcnt, if we're
2N/A * running with device ids in disksets, let's
2N/A * compare the device ids otherwise we compare
2N/A * the ctd names.
2N/A *
2N/A * There is a possibility the device ids might
2N/A * have changed. To account for that case, we
2N/A * fallback to comparing the ctd names if the
2N/A * device id comparison fails. If we aren't running
2N/A * in device id mode and a disk has moved, the ctd's
2N/A * won't match.
2N/A */
2N/A if (p->dd_dnp->devid != NULL && r->r_devid != NULL) {
2N/A (void) devid_str_decode(p->dd_dnp->devid,
2N/A &devid, NULL);
2N/A if ((devid_compare(devid, r->r_devid) == 0) ||
2N/A (strcmp(r->r_namep->drivenamep->cname,
2N/A p->dd_dnp->cname) == 0))
2N/A dbcnt++;
2N/A devid_free(devid);
2N/A } else {
2N/A if (strcmp(r->r_namep->drivenamep->cname,
2N/A p->dd_dnp->cname) == 0)
2N/A dbcnt++;
2N/A }
2N/A }
2N/A p->dd_dbcnt = dbcnt;
2N/A p->dd_dbsize = dbcnt > 0 ? nblks : 0;
2N/A }
2N/A
2N/A /* Lock the set on current set members */
2N/A if (MD_MNSET_DESC(sd)) {
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A /* If this is forced, don't lock other sides */
2N/A if (forceflg && strcmp(mynode(), nd->nd_nodename)
2N/A != 0) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A /* We already locked this side in the caller */
2N/A if (strcmp(mynode(), nd->nd_nodename) == 0) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A if (clnt_lock_set(nd->nd_nodename, sp, ep)) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A nd = nd->nd_next;
2N/A }
2N/A } else {
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 /* If this is forced, don't lock other sides */
2N/A if (forceflg && strcmp(mynode(), sd->sd_nodes[i]) != 0)
2N/A continue;
2N/A
2N/A /* We already locked this side in the caller */
2N/A if (strcmp(mynode(), sd->sd_nodes[i]) == 0)
2N/A continue;
2N/A
2N/A if (clnt_lock_set(sd->sd_nodes[i], sp, ep)) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A }
2N/A }
2N/A
2N/A if (MD_MNSET_DESC(sd)) {
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A /* If this is forced, then only care about this node */
2N/A if (forceflg && strcmp(mynode(), nd->nd_nodename)
2N/A != 0) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A if (clnt_upd_dr_dbinfo(nd->nd_nodename, sp, dd,
2N/A ep) == -1) {
2N/A if (! mdiserror(ep, MDE_NO_SET) &&
2N/A ! mdismddberror(ep, MDE_DB_NODB)) {
2N/A rval = -1;
2N/A break;
2N/A }
2N/A mdclrerror(ep);
2N/A }
2N/A nd = nd->nd_next;
2N/A }
2N/A } else {
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 /* If this is forced, then only care about this node */
2N/A if (forceflg && strcmp(mynode(), sd->sd_nodes[i]) != 0)
2N/A continue;
2N/A
2N/A if (clnt_upd_dr_dbinfo(sd->sd_nodes[i], sp, dd,
2N/A ep) == -1) {
2N/A if (! mdiserror(ep, MDE_NO_SET) &&
2N/A ! mdismddberror(ep, MDE_DB_NODB)) {
2N/A rval = -1;
2N/A break;
2N/A }
2N/A mdclrerror(ep);
2N/A }
2N/A }
2N/A }
2N/A
2N/Aout:
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
2N/A if (MD_MNSET_DESC(sd)) {
2N/A nd = sd->sd_nodelist;
2N/A while (nd) {
2N/A /* If this is forced, don't unlock other sides */
2N/A if (forceflg && strcmp(mynode(), nd->nd_nodename)
2N/A != 0) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A /* We will unlocked this side in the caller */
2N/A if (strcmp(mynode(), nd->nd_nodename) == 0) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A if (!(nd->nd_flags & MD_MN_NODE_ALIVE)) {
2N/A nd = nd->nd_next;
2N/A continue;
2N/A }
2N/A
2N/A if (clnt_unlock_set(nd->nd_nodename, cl_sk, &xep)) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A nd = nd->nd_next;
2N/A }
2N/A } else {
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 /* If this is forced, don't unlock other sides */
2N/A if (forceflg && strcmp(mynode(), sd->sd_nodes[i]) != 0)
2N/A continue;
2N/A
2N/A /* We will unlocked this side in the caller */
2N/A if (strcmp(mynode(), sd->sd_nodes[i]) == 0)
2N/A continue;
2N/A
2N/A if (clnt_unlock_set(sd->sd_nodes[i], cl_sk, &xep)) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A }
2N/A }
2N/A /* Do not clear the key, via cl_set_setkey(NULL) this is nested */
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/Astatic int
2N/Ausetag_take(set_t setno, int usetag, md_error_t *ep)
2N/A{
2N/A mddb_dtag_use_parm_t dtup;
2N/A
2N/A (void) memset(&dtup, '\0', sizeof (mddb_dtag_use_parm_t));
2N/A dtup.dtup_id = usetag;
2N/A dtup.dtup_setno = setno;
2N/A
2N/A if (metaioctl(MD_MED_USE_TAG, &dtup, &dtup.dtup_mde, NULL) != 0)
2N/A return (mdstealerror(ep, &dtup.dtup_mde));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Astatic int
2N/Auseit_take(set_t setno, md_error_t *ep)
2N/A{
2N/A mddb_accept_parm_t accp;
2N/A
2N/A (void) memset(&accp, '\0', sizeof (mddb_accept_parm_t));
2N/A accp.accp_setno = setno;
2N/A
2N/A if (metaioctl(MD_MED_ACCEPT, &accp, &accp.accp_mde, NULL) != 0)
2N/A return (mdstealerror(ep, &accp.accp_mde));
2N/A
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Update the master block with the device id information for the disks
2N/A * in the diskset. The device id information will be consumed by the
2N/A * diskset import code in case of remotely replicated disksets.
2N/A *
2N/A * For the drives that have a valid diskset mddb on them, we add the
2N/A * device id for the drive to the unused portion of the mddb.
2N/A *
2N/A * For the drives that don't have a diskset mddb on them, we add a dummy
2N/A * master block that contains the device id for the drive. A dummy master
2N/A * block is signified by changing the master block magic number, mb_magic,
2N/A * to MDDB_MAGIC_DU.
2N/A *
2N/A * This code is responsible primarily for adding the appropriate device id
2N/A * information to diskset disks that didn't have the information. This would
2N/A * typically occur when the OS has been upgraded from an OS release prior to
2N/A * Solaris 10
2N/A *
2N/A * The error path in this routine is defined as - if an error occurs while
2N/A * updating the mddb for one disk in the diskset, don't bother updating *any*
2N/A * of the mddbs because it's game over anyways as far as disaster recovery for
2N/A * that diskset is concerned.
2N/A *
2N/A * This code will need to be revisited if and when support for importing
2N/A * partial disksets is added.
2N/A *
2N/A * NOTE: This code relies heavily on the meta_repartition() working correctly
2N/A * and reformatting a drive, so that there's enough room for a dummy master
2N/A * block, every time a drive is added to a diskset. Should
2N/A * the meta_repartition() code change in future, this code will have to be
2N/A * revisited.
2N/A *
2N/A * Returns 0 on success and -1 on failure
2N/A */
2N/Aint
2N/Ameta_update_mb(mdsetname_t *sp, md_drive_desc *drivedesc, md_error_t *ep)
2N/A{
2N/A uint_t sliceno, offset;
2N/A void *mb;
2N/A mddb_mb_t *mbp;
2N/A int fd = -1;
2N/A ddi_devid_t devid = NULL;
2N/A md_drive_desc *dd;
2N/A mddrivename_t *dnp;
2N/A mdname_t *rsp;
2N/A int dbcnt;
2N/A int dbsize;
2N/A size_t len;
2N/A
2N/A mb = Malloc(DEV_BSIZE);
2N/A mbp = (mddb_mb_t *)mb;
2N/A
2N/A /*
2N/A * For every drive in the drive descriptor, iterate through all
2N/A * the mddbs present on it and check to see if mb_devid_magic is
2N/A * set. If it isn't, then update the master block with the correct
2N/A * device id information
2N/A */
2N/A for (dd = drivedesc; dd != NULL; dd = dd->dd_next) {
2N/A int i = 0;
2N/A
2N/A dnp = dd->dd_dnp;
2N/A dbcnt = dd->dd_dbcnt;
2N/A dbsize = dd->dd_dbsize;
2N/A
2N/A /*
2N/A * When the import support for remotely replicated
2N/A * disksets gets implemented, we probably want to
2N/A * inform the user that the disks won't be self
2N/A * identifying if any of these calls fails
2N/A */
2N/A if (meta_replicaslice(dnp, &sliceno, ep) != 0)
2N/A return (-1);
2N/A
2N/A if ((rsp = metaslicename(dnp, sliceno, ep)) == NULL)
2N/A return (-1);
2N/A
2N/A if ((fd = open(rsp->rname, O_RDWR)) < 0)
2N/A goto cleanup;
2N/A
2N/A /* if devid_str_decode fails, make sure devid is null */
2N/A if (devid_str_decode(dnp->devid, &devid, NULL) != 0) {
2N/A devid = NULL;
2N/A }
2N/A
2N/A do {
2N/A int push = 0;
2N/A
2N/A offset = (i * dbsize + 16);
2N/A ++i;
2N/A
2N/A if (lseek(fd, (off_t)dbtob(offset), SEEK_SET) < 0)
2N/A goto cleanup;
2N/A
2N/A if (read(fd, mbp, DEV_BSIZE) != DEV_BSIZE)
2N/A goto cleanup;
2N/A
2N/A if (crcchk((uchar_t *)mbp, (uint_t *)&mbp->mb_checksum,
2N/A (uint_t)DEV_BSIZE, (crc_skip_t *)NULL))
2N/A goto cleanup;
2N/A
2N/A /*
2N/A * If the disk is one of the ones that doesn't
2N/A * have a shared mddb on it, we put a dummy
2N/A * master block on it.
2N/A */
2N/A if (mbp->mb_devid_magic != MDDB_MAGIC_DE) {
2N/A if (dbcnt == 0) {
2N/A meta_mkdummymaster(sp, fd, 16);
2N/A break;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * if mb_setcreatetime is 0, this field was never
2N/A * filled in so do it now.
2N/A */
2N/A if ((mbp->mb_setcreatetime.tv_sec == 0) &&
2N/A (mbp->mb_setcreatetime.tv_usec == 0)) {
2N/A mbp->mb_setcreatetime =
2N/A meta_get_lb_inittime(sp, ep);
2N/A push = 1;
2N/A }
2N/A
2N/A /*
2N/A * If MDDB_MAGIC_DE is set in the
2N/A * mb_devid_magic field then we know we
2N/A * have a valid device id and we don't
2N/A * need to add it to the master block.
2N/A *
2N/A * This would have to be revisited if device
2N/A * ids change as a result of device id
2N/A * algorithms changing or somesuch.
2N/A */
2N/A if (mbp->mb_devid_magic != MDDB_MAGIC_DE) {
2N/A if (devid != NULL) {
2N/A len = devid_sizeof(devid);
2N/A if (len <= (DEV_BSIZE -
2N/A sizeof (mddb_mb_t))) {
2N/A /*
2N/A * there's enough space to
2N/A * store the devid
2N/A */
2N/A mbp->mb_devid_magic =
2N/A MDDB_MAGIC_DE;
2N/A mbp->mb_devid_len = len;
2N/A (void) memcpy(mbp->mb_devid,
2N/A (char *)devid, len);
2N/A push = 1;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * write out (push) any changes we have to the mb
2N/A */
2N/A if (push) {
2N/A crcgen((uchar_t *)mbp,
2N/A (uint_t *)&mbp->mb_checksum,
2N/A (uint_t)DEV_BSIZE, (crc_skip_t *)NULL);
2N/A
2N/A if (lseek(fd, (off_t)dbtob(offset), SEEK_SET)
2N/A < 0)
2N/A goto cleanup;
2N/A
2N/A if (write(fd, mbp, DEV_BSIZE) != DEV_BSIZE)
2N/A goto cleanup;
2N/A }
2N/A if (devid)
2N/A devid_free(devid);
2N/A } while (i < dbcnt);
2N/A (void) close(fd);
2N/A }
2N/A /* success */
2N/A return (0);
2N/A
2N/Acleanup:
2N/A if (fd != -1)
2N/A (void) close(fd);
2N/A if (devid)
2N/A devid_free(devid);
2N/A return (-1);
2N/A}
2N/A
2N/Aextern int *replicated_disk_list_built;
2N/Aextern int replicated_disk_list_built_pass1;
2N/A/*
2N/A * Exported Entry Points
2N/A */
2N/Aint
2N/Ameta_set_take(
2N/A mdsetname_t *sp,
2N/A mhd_mhiargs_t *mhiargsp,
2N/A int flags,
2N/A int usetag,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A md_set_desc *sd;
2N/A md_drive_desc *dd;
2N/A md_drive_desc *d = NULL;
2N/A char *owner = NULL;
2N/A int rval = 0;
2N/A int pathname_return = 0;
2N/A int i;
2N/A int has_set;
2N/A int matches = 0;
2N/A int numsides = 0;
2N/A md_replicalist_t *rlp = NULL;
2N/A sigset_t oldsigs;
2N/A md_setkey_t *cl_sk;
2N/A int rb_level = 0;
2N/A md_error_t xep = mdnullerror;
2N/A mdsetname_t *local_sp = NULL;
2N/A side_t side;
2N/A int ret = 0;
2N/A char *newname = NULL;
2N/A mdkey_t side_names_key;
2N/A int unrslv_replicated = 0;
2N/A mddrivenamelist_t *dnlp = NULL;
2N/A int retake_flag = 0;
2N/A unsigned long node_active[BT_BITOUL(MD_MAXSIDES)];
2N/A mdnamelist_t *nlp = NULL;
2N/A
2N/A bzero(node_active, sizeof (unsigned long) * BT_BITOUL(MD_MAXSIDES));
2N/A
2N/A if ((flags & TAKE_USETAG) || (flags & TAKE_USEIT)) {
2N/A if (flags & TAKE_USETAG) {
2N/A if (usetag_take(sp->setno, usetag, ep))
2N/A return (-1);
2N/A } else {
2N/A if (useit_take(sp->setno, ep))
2N/A return (-1);
2N/A }
2N/A
2N/A if (meta_resync_all(sp, MD_DEF_RESYNC_BUF_SIZE, ep) != 0)
2N/A mdclrerror(ep);
2N/A }
2N/A
2N/A /* Do we own the set? */
2N/A i = own_set(sp, &owner, (flags & TAKE_FORCE), ep);
2N/A if (! mdisok(ep)) {
2N/A if (owner != NULL)
2N/A Free(owner);
2N/A return (-1);
2N/A }
2N/A
2N/A if (i == MD_SETOWNER_NO) {
2N/A (void) mddserror(ep, MDE_DS_NOTOWNER, sp->setno, owner, NULL,
2N/A sp->setname);
2N/A if (owner != NULL)
2N/A Free(owner);
2N/A return (-1);
2N/A }
2N/A
2N/A if (owner != NULL) {
2N/A Free(owner);
2N/A owner = NULL;
2N/A }
2N/A
2N/A /* We already own it, we are done. */
2N/A if (i == MD_SETOWNER_YES)
2N/A return (0);
2N/A
2N/A if ((sd = metaget_setdesc(sp, &xep)) == NULL)
2N/A return (-1);
2N/A
2N/A /* You can not take ownership of a set that has no drives */
2N/A if (sd->sd_flags & MD_SR_MB_DEVID)
2N/A dd = metaget_drivedesc(sp, MD_BASICNAME_OK | PRINT_FAST, ep);
2N/A else
2N/A dd = metaget_drivedesc(sp, MD_BASICNAME_OK, ep);
2N/A
2N/A if (dd == NULL) {
2N/A if (! mdisok(ep))
2N/A return (-1);
2N/A return (0);
2N/A }
2N/A
2N/A /* END CHECK CODE */
2N/A
2N/A md_rb_sig_handling_on();
2N/A
2N/A /* Lock the set on our side */
2N/A if (clnt_lock_set(mynode(), sp, ep)) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Find the "side" value so that it can be used to deal with
2N/A * the devids.
2N/A */
2N/A side = getnodeside(mynode(), sd);
2N/A
2N/A if (side == MD_SIDEWILD) {
2N/A (void) mddserror(ep, MDE_DS_HOSTNOSIDE, sp->setno, mynode(),
2N/A NULL, mynode());
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * A local sets' side 0 references records associated with
2N/A * that node's local set. As this is a non-local set, "side"
2N/A * must be modified (by adding a SKEW) before we reference
2N/A * records in the local set [setno = 0] for the non-local set
2N/A * [setno = 1..n].
2N/A */
2N/A side += SKEW;
2N/A
2N/A /*
2N/A * If this set had been previously imported as a partial replicated
2N/A * diskset, then must attempt to updated any unresolved drive
2N/A * records in diskset with new devid information. Must set
2N/A * flags in drivedesc list before loading up set so that the
2N/A * md driver will fix up names and devids correctly in the
2N/A * locator block.
2N/A */
2N/A if (sd->sd_flags & MD_SR_UNRSLV_REPLICATED) {
2N/A md_im_names_t cnames = { 0, NULL};
2N/A ddi_devid_t old_devid, new_devid;
2N/A char *search_path = "/dev";
2N/A devid_nmlist_t *nmlist;
2N/A int indx;
2N/A mddrivenamelist_t **dnlpp = &dnlp;
2N/A
2N/A if (meta_list_disks(ep, &cnames) != 0) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A for (indx = 0; indx < cnames.min_count; ++indx) {
2N/A mddrivename_t *dnp;
2N/A mdsetname_t *sp = metasetname(MD_LOCAL_NAME, ep);
2N/A int fd = -1;
2N/A ddi_devid_t devid1;
2N/A char *cdevidp;
2N/A int len;
2N/A char *fp;
2N/A
2N/A /*
2N/A * We may have name collision here so we need to get
2N/A * the dnp using the devid and not the name.
2N/A */
2N/A len = strlen(cnames.min_names[indx]) + strlen("s0");
2N/A if ((fp = (char *)Malloc(len+1)) == NULL) {
2N/A (void) mdsyserror(ep, ENOMEM, NULL);
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A (void) snprintf(fp, len + 1, "%ss0",
2N/A cnames.min_names[indx]);
2N/A if ((fd = open(fp, O_RDONLY|O_NDELAY)) < 0) {
2N/A (void) mdsyserror(ep, EIO, fp);
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A Free(fp);
2N/A /* if no device id, what error?) */
2N/A if (devid_get(fd, &devid1) != 0) {
2N/A (void) mdsyserror(ep, EIO, fp);
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A if (close(fd) < 0) {
2N/A (void) mdsyserror(ep, EIO, fp);
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A cdevidp = devid_str_encode(devid1, NULL);
2N/A if (cdevidp == NULL) {
2N/A (void) mdsyserror(ep, EIO, fp);
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A devid_free(devid1);
2N/A dnp = metadrivenamebydevid(&sp, cdevidp,
2N/A cnames.min_names[indx], ep);
2N/A devid_str_free(cdevidp);
2N/A if (dnp == NULL) {
2N/A /*
2N/A * Assuming we're interested in knowing about
2N/A * whatever error occurred, but not in stopping.
2N/A */
2N/A mde_perror(ep, cnames.min_names[indx]);
2N/A mdclrerror(ep);
2N/A continue;
2N/A }
2N/A
2N/A dnlpp = meta_drivenamelist_append_wrapper(dnlpp, dnp);
2N/A }
2N/A /* Reget sd and dd since freed by meta_prune_cnames. */
2N/A if ((sd = metaget_setdesc(sp, ep)) == NULL) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A if (sd->sd_flags & MD_SR_MB_DEVID)
2N/A dd = metaget_drivedesc(sp,
2N/A MD_BASICNAME_OK | PRINT_FAST, ep);
2N/A else
2N/A dd = metaget_drivedesc(sp, MD_BASICNAME_OK, ep);
2N/A /* If ep has error, then there was a failure, set rval */
2N/A if (!mdisok(ep)) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A /* Builds global replicated disk list */
2N/A replicated_disk_list_built = &replicated_disk_list_built_pass1;
2N/A
2N/A /* If success, then clear error structure */
2N/A if (build_replicated_disks_list(ep, dnlp) == 1)
2N/A mdclrerror(ep);
2N/A /* If ep has error, then there was a failure, set rval */
2N/A if (! mdisok(ep)) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A for (d = dd; d != NULL; d = d->dd_next) {
2N/A if (d->dd_flags & MD_DR_UNRSLV_REPLICATED) {
2N/A /* Get old devid from drive record */
2N/A (void) devid_str_decode(d->dd_dnp->devid,
2N/A &old_devid, NULL);
2N/A
2N/A /*
2N/A * If the devid stored in the drive record
2N/A * (old_devid) matches a devid known by
2N/A * the system, then this disk has already
2N/A * been partially resolved. This situation
2N/A * could occur if a panic happened during a
2N/A * previous take of this diskset.
2N/A * Set flag to later handle fixing the master
2N/A * block on disk and turning off the unresolved
2N/A * replicated flag.
2N/A */
2N/A if (meta_deviceid_to_nmlist(search_path,
2N/A (ddi_devid_t)old_devid,
2N/A DEVID_MINOR_NAME_ALL,
2N/A &nmlist) == 0) {
2N/A d->dd_flags |= MD_DR_FIX_MB_DID;
2N/A retake_flag = 1;
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * If the devid stored in the drive record
2N/A * is on the list of replicated disks found
2N/A * during a system scan then set both flags
2N/A * so that the locator block, namespaces
2N/A * (diskset and local set), master block
2N/A * and unresolved replicated flag are updated.
2N/A */
2N/A new_devid = replicated_list_lookup(
2N/A devid_sizeof((ddi_devid_t)old_devid),
2N/A old_devid);
2N/A devid_free(old_devid);
2N/A
2N/A /*
2N/A * If devid stored in the drive record is
2N/A * not found then set flag to mark
2N/A * that set is still unresolved and
2N/A * continue to next drive record.
2N/A */
2N/A if (new_devid == NULL) {
2N/A unrslv_replicated = 1;
2N/A continue;
2N/A }
2N/A
2N/A /*
2N/A * Set flags to fix up the master block,
2N/A * locator block of the diskset, diskset
2N/A * namespace and the local set namespace.
2N/A */
2N/A d->dd_flags |= (MD_DR_FIX_MB_DID |
2N/A MD_DR_FIX_LB_NM_DID);
2N/A retake_flag = 1;
2N/A }
2N/A }
2N/A
2N/A }
2N/A
2N/A /*
2N/A * Check the local devid namespace to see if the disks
2N/A * have been moved. Use the local set first of all as this contains
2N/A * entries for the disks in the set.
2N/A *
2N/A * This is being done before the tk_own_bydd because the disks
2N/A * in the dd list could be wrong! But it should be done with the lock
2N/A * held for the set.
2N/A */
2N/A local_sp = metasetname(MD_LOCAL_NAME, ep);
2N/A for (d = dd; d != NULL; d = d->dd_next) {
2N/A /*
2N/A * Actually do the check of the disks.
2N/A */
2N/A ret = meta_upd_ctdnames(&local_sp, 0, side, 0, d->dd_dnp,
2N/A &newname, ep);
2N/A
2N/A if ((ret == METADEVADM_ERR) ||
2N/A (ret == METADEVADM_DSKNAME_ERR)) {
2N/A /* check failed in some unknown manner */
2N/A rval = -1;
2N/A goto out;
2N/A } else if (ret == METADEVADM_DISKMOVE) {
2N/A
2N/A /*
2N/A * Update the dd namelist so that the rpc.metamhd
2N/A * gets the correct disks to reserve - it is the rname
2N/A * we are interested in.
2N/A */
2N/A if (newname != NULL) {
2N/A char *save_devid;
2N/A /*
2N/A * Need to save the side names key as this
2N/A * points to the namespace entry that will
2N/A * need to be updated. In addition the call
2N/A * to meta_make_sidenmlist does not actually
2N/A * set the namespace key.
2N/A */
2N/A side_names_key = d->dd_dnp->side_names_key;
2N/A
2N/A /*
2N/A * There is the possibility that there
2N/A * will be multiple disks with the same
2N/A * name but different devids in the
2N/A * drivelist. Because of this, we need
2N/A * to look for a new dnp based on devid
2N/A * and not name.
2N/A */
2N/A save_devid = Strdup(d->dd_dnp->devid);
2N/A metafreedrivename(d->dd_dnp);
2N/A d->dd_dnp = metadrivenamebydevid(&sp,
2N/A save_devid, newname, ep);
2N/A Free(save_devid);
2N/A Free(newname);
2N/A /*
2N/A * null newname so we are reset for next time
2N/A * through
2N/A */
2N/A newname = NULL;
2N/A ret = meta_make_sidenmlist(sp,
2N/A d->dd_dnp, 0, NULL, ep);
2N/A d->dd_dnp->side_names_key = side_names_key;
2N/A if (ret == -1) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A
2N/A
2N/A RB_TEST(1, "take", ep)
2N/A
2N/A RB_PREEMPT;
2N/A rb_level = 1; /* level 1 */
2N/A
2N/A RB_TEST(2, "take", ep)
2N/A
2N/A if (!MD_ATSET_DESC(sd)) {
2N/A if (tk_own_bydd(sp, dd, mhiargsp,
2N/A flags & MD_IM_PARTIAL_DISKSET, ep))
2N/A goto rollback;
2N/A }
2N/A
2N/A RB_TEST(3, "take", ep)
2N/A
2N/A RB_PREEMPT;
2N/A rb_level = 2; /* level 2 */
2N/A
2N/A RB_TEST(4, "take", ep)
2N/A
2N/A if (clnt_stimeout(mynode(), sp, mhiargsp, ep) == -1)
2N/A goto rollback;
2N/A
2N/A if (setup_db_bydd(sp, dd, (flags & TAKE_FORCE), ep) == -1) {
2N/A if (! mdismddberror(ep, MDE_DB_ACCOK) &&
2N/A ! mdismddberror(ep, MDE_DB_TAGDATA))
2N/A goto rollback;
2N/A mdclrerror(ep);
2N/A }
2N/A
2N/A RB_TEST(5, "take", ep)
2N/A
2N/A RB_PREEMPT;
2N/A rb_level = 3; /* level 3 */
2N/A
2N/A RB_TEST(6, "take", ep)
2N/A
2N/A /* Snarf set of traditional diskset doesn't use stale information */
2N/A if (snarf_set(sp, FALSE, ep)) {
2N/A if (mdismddberror(ep, MDE_DB_STALE) ||
2N/A mdismddberror(ep, MDE_DB_ACCOK) ||
2N/A mdismddberror(ep, MDE_DB_TAGDATA)) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A if (! mdismddberror(ep, MDE_DB_NODB) &&
2N/A ! mdismddberror(ep, MDE_DB_NOTOWNER))
2N/A goto rollback;
2N/A
2N/A /*
2N/A * Look at the set on all other hosts, if every other host
2N/A * has the same set with a larger genid, then we destroy this
2N/A * copy.
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 /* Skip this node */
2N/A if (strcmp(sd->sd_nodes[i], mynode()) == 0)
2N/A continue;
2N/A
2N/A numsides++;
2N/A
2N/A has_set = nodehasset(sp, sd->sd_nodes[i],
2N/A NHS_NST_EQ_G_GT, &xep);
2N/A
2N/A if (has_set < 0) {
2N/A if (! mdiserror(&xep, MDE_NO_SET) &&
2N/A ! mdismddberror(&xep, MDE_DB_NODB))
2N/A goto rollback;
2N/A matches++;
2N/A mdclrerror(&xep);
2N/A continue;
2N/A }
2N/A
2N/A if (has_set)
2N/A matches++;
2N/A }
2N/A
2N/A /* Destroy the set */
2N/A if (numsides > 0 && (numsides - matches) == 0) {
2N/A if (meta_set_destroy(sp, FALSE, &xep))
2N/A mdclrerror(&xep);
2N/A (void) mddserror(ep, MDE_DS_SETCLEANUP, sp->setno,
2N/A sp->setname, NULL, mynode());
2N/A rval = -1;
2N/A }
2N/A goto rollback;
2N/A }
2N/A
2N/A /*
2N/A * If an unresolved replicated diskset, fix up diskset
2N/A * and local namespaces, master block and drive record
2N/A * with the new devid. If all drives in diskset are
2N/A * now resolved, then clear set unresolved replicated flag.
2N/A * If an error is encountered, don't fail the take, but
2N/A * don't proceed any further in resolving the replicated disks.
2N/A */
2N/A if (sd->sd_flags & MD_SR_UNRSLV_REPLICATED) {
2N/A /* Fix up diskset and local namespaces with new devids */
2N/A meta_unrslv_replicated_nm(sp, dd, dnlp, ep);
2N/A if (mdisok(ep)) {
2N/A /* Fix up master block with new devids */
2N/A meta_unrslv_replicated_mb(sp, dd, dnlp, ep);
2N/A }
2N/A
2N/A /* If all drives are resolved, set OK flag in set record. */
2N/A if (mdisok(ep) && (unrslv_replicated == 0)) {
2N/A /* Ignore failure since no bad effect. */
2N/A (void) clnt_upd_sr_flags(mynode(), sp, MD_SR_OK, ep);
2N/A }
2N/A mdclrerror(ep);
2N/A
2N/A }
2N/A
2N/A /*
2N/A * meta_getalldevs() will ultimately force devfsadmd to create
2N/A * the /dev links for all the configured metadevices if they
2N/A * do not already exist. This ensures that once the set is
2N/A * owned all the metadevices are accessible as opposed to waiting
2N/A * for devfsadmd to create them.
2N/A */
2N/A if (meta_getalldevs(sp, &nlp, FALSE, ep) != 0) {
2N/A metafreenamelist(nlp);
2N/A goto rollback;
2N/A }
2N/A
2N/A metafreenamelist(nlp);
2N/A
2N/A pathname_return = pathname_reload(&sp, sp->setno, ep);
2N/A if ((pathname_return == METADEVADM_ERR) ||
2N/A (pathname_return == METADEVADM_DSKNAME_ERR)) {
2N/A goto rollback;
2N/A }
2N/A
2N/A
2N/A if (metareplicalist(sp, (MD_BASICNAME_OK | PRINT_FAST), &rlp, ep) < 0)
2N/A goto rollback;
2N/A
2N/A if (upd_dr_dbinfo(sp, sd, dd, rlp, (flags & TAKE_FORCE), ep) < 0) {
2N/A metafreereplicalist(rlp);
2N/A goto rollback;
2N/A }
2N/A
2N/A metafreereplicalist(rlp);
2N/A
2N/A /*
2N/A * If the set doesn't have the MD_SR_MB_DEVID bit set, i.e
2N/A * the drives in the set don't have the device id information,
2N/A * then stick it in if possible.
2N/A *
2N/A * If updating the master block fails for whatever reason, it's
2N/A * okay. It just means the disk(s) in the diskset won't be self
2N/A * identifying.
2N/A */
2N/A if (!(sd->sd_flags & MD_SR_MB_DEVID)) {
2N/A /* Lock the set on current set members */
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 /* We already locked this side */
2N/A if (strcmp(mynode(), sd->sd_nodes[i]) == 0)
2N/A continue;
2N/A
2N/A if (clnt_lock_set(sd->sd_nodes[i], sp, ep)) {
2N/A /*
2N/A * Ignore any RPC errors on a force
2N/A * take. The set will have been taken
2N/A * above and we still need to continue.
2N/A */
2N/A if (flags & TAKE_FORCE)
2N/A continue;
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A BT_SET(node_active, i);
2N/A }
2N/A rb_level = 4; /* level 4 */
2N/A
2N/A if (meta_update_mb(sp, dd, ep) == 0)
2N/A /* update the sr_flags on all hosts */
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 /*
2N/A * Only update those nodes that
2N/A * are active (ie those that the
2N/A * set is locked on).
2N/A */
2N/A if (!BT_TEST(node_active, i))
2N/A continue;
2N/A
2N/A if (clnt_upd_sr_flags(sd->sd_nodes[i],
2N/A sp, (sd->sd_flags | MD_SR_MB_DEVID), ep))
2N/A goto rollback;
2N/A }
2N/A
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
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 /* Unlocked of this side is done later */
2N/A if (strcmp(mynode(), sd->sd_nodes[i]) == 0)
2N/A continue;
2N/A
2N/A /* no point calling dead nodes */
2N/A if (!BT_TEST(node_active, i))
2N/A continue;
2N/A
2N/A if (clnt_unlock_set(sd->sd_nodes[i], cl_sk, &xep)) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * If we get here, we need to unlock the set before the resync
2N/A * gets called, otherwise the "daemon" will hold the set lock
2N/A * until the resync is done!
2N/A */
2N/A
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
2N/A if (clnt_unlock_set(mynode(), cl_sk, &xep)) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A cl_set_setkey(NULL);
2N/A
2N/A md_rb_sig_handling_off(md_got_sig(), md_which_sig());
2N/A
2N/A /* We try to get things resync'ed, but this can fail */
2N/A mdclrerror(&xep);
2N/A if (meta_resync_all(sp, MD_DEF_RESYNC_BUF_SIZE, &xep) != 0) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A
2N/A RB_TEST(7, "take", ep)
2N/A
2N/A /*
2N/A * In order to resolve the namespace major driver names and
2N/A * to have the subdrivers attempt to re-associate devts from
2N/A * the newly resolved replicated device ids, return a '2'.
2N/A * This instructs metaset to release the diskset and re-take.
2N/A *
2N/A * Return a 2 if
2N/A * - no error was detected on the take
2N/A * - a replicated unresolved devid was resolved during take
2N/A * - take isn't being called during an import
2N/A * - this isn't already a re-take situation
2N/A */
2N/A if ((rval == 0) && (retake_flag == 1) &&
2N/A ((flags & (TAKE_RETAKE | TAKE_IMP)) == 0)) {
2N/A rval = 2;
2N/A }
2N/A
2N/A return (rval);
2N/A
2N/Aout:
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
2N/A if (clnt_unlock_set(mynode(), cl_sk, &xep)) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A if (!(sd->sd_flags & MD_SR_MB_DEVID) && (rb_level > 2)) {
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 /* We already unlocked this side */
2N/A if (strcmp(mynode(), sd->sd_nodes[i]) == 0)
2N/A continue;
2N/A
2N/A /* no point calling dead nodes */
2N/A if (!BT_TEST(node_active, i))
2N/A continue;
2N/A
2N/A if (clnt_unlock_set(sd->sd_nodes[i], cl_sk, &xep)) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A }
2N/A }
2N/A cl_set_setkey(NULL);
2N/A
2N/A md_rb_sig_handling_off(md_got_sig(), md_which_sig());
2N/A
2N/A return (rval);
2N/A
2N/Arollback:
2N/A /* Make sure we are blocking all signals */
2N/A if (procsigs(TRUE, &oldsigs, &xep) < 0)
2N/A mdclrerror(&xep);
2N/A
2N/A rval = -1;
2N/A
2N/A /* level 4 */
2N/A if (rb_level > 3) {
2N/A if (sd->sd_flags & MD_SR_MB_DEVID) {
2N/A /* update the sr_flags on all hosts */
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 /* no point calling dead nodes */
2N/A if (!BT_TEST(node_active, i))
2N/A continue;
2N/A
2N/A if (clnt_upd_sr_flags(sd->sd_nodes[i], sp,
2N/A (sd->sd_flags & ~MD_SR_MB_DEVID), &xep))
2N/A mdclrerror(&xep);
2N/A }
2N/A }
2N/A
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
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 /* We will unlocked this side below */
2N/A if (strcmp(mynode(), sd->sd_nodes[i]) == 0)
2N/A continue;
2N/A
2N/A /* no point calling dead nodes */
2N/A if (!BT_TEST(node_active, i))
2N/A continue;
2N/A
2N/A if (clnt_unlock_set(sd->sd_nodes[i], cl_sk, &xep))
2N/A mdclrerror(&xep);
2N/A }
2N/A }
2N/A
2N/A /* level 3 */
2N/A if (rb_level > 2) {
2N/A if (halt_set(sp, &xep))
2N/A mdclrerror(&xep);
2N/A }
2N/A
2N/A /* level 2 */
2N/A if (rb_level > 1) {
2N/A if (clnt_stimeout(mynode(), sp, &defmhiargs, &xep) == -1)
2N/A mdclrerror(&xep);
2N/A }
2N/A
2N/A /* level 1 */
2N/A if (rb_level > 0) {
2N/A if (!MD_ATSET_DESC(sd)) {
2N/A if (rel_own_bydd(sp, dd, FALSE, &xep))
2N/A mdclrerror(&xep);
2N/A }
2N/A }
2N/A
2N/A /* level 0 */
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
2N/A if (clnt_unlock_set(mynode(), cl_sk, &xep))
2N/A mdclrerror(&xep);
2N/A cl_set_setkey(NULL);
2N/A
2N/A /* release signals back to what they were on entry */
2N/A if (procsigs(FALSE, &oldsigs, &xep) < 0)
2N/A mdclrerror(&xep);
2N/A
2N/A md_rb_sig_handling_off(md_got_sig(), md_which_sig());
2N/A
2N/A return (rval);
2N/A}
2N/A
2N/Aint
2N/Ameta_set_release(
2N/A mdsetname_t *sp,
2N/A md_error_t *ep
2N/A)
2N/A{
2N/A int rval = 0;
2N/A md_drive_desc *dd;
2N/A mhd_mhiargs_t mhiargs;
2N/A sigset_t oldsigs;
2N/A md_setkey_t *cl_sk;
2N/A int rb_level = 0;
2N/A md_error_t xep = mdnullerror;
2N/A
2N/A /* Make sure we own the set */
2N/A if (meta_check_ownership(sp, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* Get the drive descriptors */
2N/A if ((dd = metaget_drivedesc(sp, (MD_BASICNAME_OK | PRINT_FAST),
2N/A ep)) == NULL)
2N/A if (! mdisok(ep))
2N/A return (-1);
2N/A
2N/A /* Get timeout values in case we need to roll back this release */
2N/A (void) memset(&mhiargs, '\0', sizeof (mhiargs));
2N/A if (clnt_gtimeout(mynode(), sp, &mhiargs, ep) != 0)
2N/A return (-1);
2N/A
2N/A /* END CHECK CODE */
2N/A
2N/A md_rb_sig_handling_on();
2N/A
2N/A /* Lock the set on our side */
2N/A if (clnt_lock_set(mynode(), sp, ep)) {
2N/A rval = -1;
2N/A goto out;
2N/A }
2N/A
2N/A RB_TEST(1, "release", ep)
2N/A
2N/A RB_PREEMPT;
2N/A rb_level = 1; /* level 1 */
2N/A
2N/A RB_TEST(2, "release", ep)
2N/A
2N/A if (halt_set(sp, ep))
2N/A goto rollback;
2N/A
2N/A RB_TEST(3, "release", ep)
2N/A
2N/A RB_PREEMPT;
2N/A rb_level = 2; /* level 2 */
2N/A
2N/A RB_TEST(4, "release", ep)
2N/A
2N/A if (rel_own_bydd(sp, dd, FALSE, ep))
2N/A goto rollback;
2N/A
2N/A RB_TEST(5, "release", ep)
2N/A
2N/A RB_PREEMPT;
2N/A rb_level = 3; /* level 3 */
2N/A
2N/A RB_TEST(6, "release", ep)
2N/A
2N/A if (clnt_stimeout(mynode(), sp, &defmhiargs, ep) == -1)
2N/A goto rollback;
2N/A
2N/A RB_TEST(7, "release", ep)
2N/A
2N/Aout:
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
2N/A if (clnt_unlock_set(mynode(), cl_sk, &xep)) {
2N/A if (rval == 0)
2N/A (void) mdstealerror(ep, &xep);
2N/A rval = -1;
2N/A }
2N/A cl_set_setkey(NULL);
2N/A
2N/A md_rb_sig_handling_off(md_got_sig(), md_which_sig());
2N/A
2N/A return (rval);
2N/A
2N/Arollback:
2N/A /* Make sure we are blocking all signals */
2N/A if (procsigs(TRUE, &oldsigs, &xep) < 0)
2N/A mdclrerror(&xep);
2N/A
2N/A rval = -1;
2N/A
2N/A /* level 3 */
2N/A if (rb_level > 2) {
2N/A if (clnt_stimeout(mynode(), sp, &mhiargs, &xep) == -1)
2N/A mdclrerror(&xep);
2N/A }
2N/A
2N/A /* level 2 */
2N/A if (rb_level > 1) {
2N/A if (tk_own_bydd(sp, dd, &mhiargs, FALSE, &xep))
2N/A mdclrerror(&xep);
2N/A }
2N/A
2N/A /* level 1 */
2N/A if (rb_level > 0) {
2N/A if (setup_db_bydd(sp, dd, TRUE, &xep) == -1)
2N/A mdclrerror(&xep);
2N/A
2N/A /* Snarf set of trad diskset doesn't use stale information */
2N/A if (snarf_set(sp, FALSE, &xep))
2N/A mdclrerror(&xep);
2N/A }
2N/A
2N/A /* level 0 */
2N/A cl_sk = cl_get_setkey(sp->setno, sp->setname);
2N/A if (clnt_unlock_set(mynode(), cl_sk, &xep))
2N/A mdclrerror(&xep);
2N/A cl_set_setkey(NULL);
2N/A
2N/A /* release signals back to what they were on entry */
2N/A if (procsigs(FALSE, &oldsigs, &xep) < 0)
2N/A mdclrerror(&xep);
2N/A
2N/A md_rb_sig_handling_off(md_got_sig(), md_which_sig());
2N/A
2N/A return (rval);
2N/A}