OpenSolaris_b135/lib/lvm/libmeta/common/meta_check.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * 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.
 * 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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * Just in case we're not in a build environment, make sure that
 * TEXT_DOMAIN gets set to something.
 */
#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SYS_TEST"
#endif

/*
 * check componets
 */

#include <meta.h>
#include "meta_lib_prv.h"

#include <sys/mnttab.h>
#include <sys/swap.h>
#include <devid.h>
#include <sys/dumpadm.h>

/* possible returns from meta_check_samedrive */
#define	CANT_TELL		-1
#define	NOT_SAMEDRIVE		0
#define	IDENTICAL_NAME_DEVT	1
#define	IDENTICAL_DEVIDS	2

/*
 * static list(s)
 */
typedef struct dev_list {
	char			*dev_name;
	ddi_devid_t		devid;
	struct dev_list		*dev_nxt;
} dev_list_t;

static dev_list_t	*devnamelist = NULL;

static char	*skip_these_mntents[] = {
	"nfs",
	"autofs",
	"proc",
	"tmpfs",
	"cachefs",
	"rfs",
	"fd",
	"mntfs",
	"lofs",
	"devfs",
	"dev",
	"ctfs",
	"objfs",
	"sharefs",
	NULL
};

/*
 * free swap info
 */
static void
free_swapinfo(
	struct swaptable	*swtp
)
{
	int			i;

	if (swtp == NULL)
		return;

	for (i = 0; (i < swtp->swt_n); ++i) {
		if (swtp->swt_ent[i].ste_path != NULL)
			Free(swtp->swt_ent[i].ste_path);
	}

	Free(swtp);
}

/*
 * get swap info
 */
static int
get_swapinfo(
	struct swaptable	**swtpp,
	int			*nswap,
	md_error_t		*ep
)
{
	int			i;
	size_t			swtsize;

	*swtpp = NULL;

	/* get number of entries */
	if ((*nswap = swapctl(SC_GETNSWP, NULL)) < 0) {
		return (mdsyserror(ep, errno, "swapctl(SC_GETNSWP)"));
	}

	/* allocate structure */
	swtsize = sizeof ((*swtpp)->swt_n) +
	    ((*nswap) * sizeof ((*swtpp)->swt_ent[0]));
	*swtpp = (struct swaptable *)Zalloc(swtsize);
	(*swtpp)->swt_n = *nswap;
	for (i = 0; (i < (*nswap)); ++i)
		(*swtpp)->swt_ent[i].ste_path = Zalloc(MAXPATHLEN);

	/* get info */
	if (((*nswap) = swapctl(SC_LIST, (*swtpp))) < 0) {
		(void) mdsyserror(ep, errno, "swapctl(SC_LIST)");
		free_swapinfo(*swtpp);
		return (-1);
	}

	/* return success */
	return (0);
}

/*
 * check whether device is swapped on
 */
static int
meta_check_swapped(
	mdsetname_t		*sp,
	mdname_t		*np,
	md_error_t		*ep
)
{
	struct swaptable	*swtp;
	int			nswap;
	int			i;
	int			rval = 0;

	/* should have a set */
	assert(sp != NULL);

	/* get swap info */
	if (get_swapinfo(&swtp, &nswap, ep) != 0)
		return (-1);

	/* look for match */
	for (i = 0; ((i < nswap) && (rval == 0)); ++i) {
		mdname_t	*snp;

		if ((snp = metaname(&sp, swtp->swt_ent[i].ste_path,
		    UNKNOWN, ep)) == NULL) {
			mdclrerror(ep);
			continue;
		}
		if (np->dev == snp->dev) {
			rval = mddeverror(ep, MDE_IS_SWAPPED,
			    np->dev, np->cname);
		} else { /* not swap - does it overlap */
			rval = meta_check_overlap(snp->cname, np, 0, -1,
			    snp, 0, -1, ep);
			if (rval != 0) {
				(void) mdoverlaperror(ep, MDE_OVERLAP_SWAP,
				    np->cname, NULL, snp->cname);
			}
		}
	}
	free_swapinfo(swtp);

	/* return success */
	return (rval);
}

/*
 * Is a driver currently swapped on?
 */
int
meta_check_driveswapped(
	mdsetname_t		*sp,
	mddrivename_t		*dnp,
	md_error_t		*ep
)
{
	struct swaptable	*swtp;
	int			nswap;
	int			i;
	int			rval = 0;

	/* should have a set */
	assert(sp != NULL);

	/* get swap info */
	if (get_swapinfo(&swtp, &nswap, ep) != 0)
		return (-1);

	/* look for match */
	for (i = 0; (i < nswap); ++i) {
		mdname_t	*snp;

		if ((snp = metaname(&sp, swtp->swt_ent[i].ste_path,
		    LOGICAL_DEVICE, ep)) == NULL) {
			mdclrerror(ep);
			continue;
		}

		if (strcmp(dnp->cname, snp->drivenamep->cname) == 0) {
			rval = mddeverror(ep, MDE_IS_SWAPPED, NODEV64,
			    dnp->cname);
		}
	}
	free_swapinfo(swtp);

	/* return success */
	return (rval);
}

/*
 * check whether device is a dump device
 */
static int
meta_check_dump(
	mdsetname_t	*sp,
	mdname_t	*np,
	md_error_t	*ep
)
{
	int		rval = 0;
	int		dump_fd;
	char		device[MAXPATHLEN];


	if ((dump_fd = open("/dev/dump", O_RDONLY)) < 0)
		return (mdsyserror(ep, errno, "/dev/dump"));

	if (ioctl(dump_fd, DIOCGETDEV, device) != -1) {
		mdname_t	*dump_np;

		if ((dump_np = metaname(&sp, device, UNKNOWN, ep)) == NULL) {
			mdclrerror(ep);
			(void) close(dump_fd);
			return (0);
		}

		if (np->dev == dump_np->dev) {
			rval = mddeverror(ep, MDE_IS_DUMP,
			    np->dev, np->cname);
		} else { /* not a dump device - but does it overlap? */
			rval = meta_check_overlap(dump_np->cname, np, 0, -1,
			    dump_np, 0, -1, ep);
			if (rval != 0) {
				(void) mdoverlaperror(ep, MDE_OVERLAP_DUMP,
				    np->cname, NULL, dump_np->cname);
			}
		}
	}
	(void) close(dump_fd);
	return (rval);
}

/*
 * check whether device is mounted
 */
static int
meta_check_mounted(
	mdsetname_t	*sp,
	mdname_t	*np,
	md_error_t	*ep
)
{
	FILE		*mfp;
	struct mnttab	m;
	int		rval = 0;
	char		mountp[MNT_LINE_MAX];
	char		mnt_special[MNT_LINE_MAX];

	/* should have a set */
	assert(sp != NULL);

	/* look in mnttab */
	if ((mfp = open_mnttab()) == NULL)
		return (mdsyserror(ep, errno, MNTTAB));
	while ((getmntent(mfp, &m) == 0) && (rval == 0)) {
		char		**fstype = skip_these_mntents;
		int		skipit = 0;
		mdname_t	*mnp;

		if ((m.mnt_special == NULL) || (m.mnt_mountp == NULL))
			continue;

		if (m.mnt_mountp[0] != '/')
			continue;

		while (*fstype != NULL)
			if (strcmp(m.mnt_fstype, *fstype++) == 0) {
				skipit++;
				break;
			}

		if (skipit == 1)
			continue;

		(void) strcpy(mountp, m.mnt_mountp);
		(void) strcpy(mnt_special, m.mnt_special);

		if ((mnp = metaname(&sp, mnt_special, UNKNOWN, ep)) == NULL) {
			mdclrerror(ep);
			continue;
		}

		if (np->dev == mnp->dev) {
			rval = mduseerror(ep, MDE_IS_MOUNTED,
			    np->dev, mountp, np->cname);
		} else { /* device isn't in mnttab - does it overlap? */
			rval = meta_check_overlap(mnp->cname, np, 0, -1,
			    mnp, 0, -1, ep);
			if (rval != 0) {
				(void) mdoverlaperror(ep, MDE_OVERLAP_MOUNTED,
				    np->cname, mountp, mnp->cname);
			}
		}
	}

	/* return success */
	return (rval);
}


/*
 * Is a file system currently mounted on this disk drive?
 */
int
meta_check_drivemounted(
	mdsetname_t	*sp,
	mddrivename_t	*dnp,
	md_error_t	*ep
)
{
	FILE		*mfp;
	struct mnttab	m;
	int		rval = 0;
	char		mountp[MNT_LINE_MAX];
	char		mnt_special[MNT_LINE_MAX];

	/* should have a set */
	assert(sp != NULL);

	/* look in mnttab */
	if ((mfp = open_mnttab()) == NULL)
		return (mdsyserror(ep, errno, MNTTAB));
	while ((getmntent(mfp, &m) == 0) && (rval == 0)) {
		char		**fstype = skip_these_mntents;
		int		skipit = 0;
		mdname_t	*mnp;

		if ((m.mnt_special == NULL) || (m.mnt_mountp == NULL))
			continue;

		if (m.mnt_mountp[0] != '/')
			continue;

		while (*fstype != NULL)
			if (strcmp(m.mnt_fstype, *fstype++) == 0) {
				skipit++;
				break;
			}

		if (skipit == 1)
			continue;

		(void) strcpy(mountp, m.mnt_mountp);
		(void) strcpy(mnt_special, m.mnt_special);
		if ((mnp = metaname(&sp, mnt_special,
		    LOGICAL_DEVICE, ep)) == NULL) {
			mdclrerror(ep);
			continue;
		}
		if (strcmp(dnp->cname, mnp->drivenamep->cname) == 0) {
			rval = mduseerror(ep, MDE_IS_MOUNTED, NODEV64,
			    mountp, dnp->cname);
		}
	}

	/* return success */
	return (rval);
}

/*
 * Check to see if the specified name is already in use or overlaps
 * with a device already in use. Checks are made to determine whether
 * the device is mounted, is a swap device, or a dump device.  In each
 * case if the device is not in use then an overlap check is done to ensure
 * that the specified slice does not overlap.
 */
int
meta_check_inuse(
	mdsetname_t	*sp,
	mdname_t	*np,
	mdinuseopts_t	inuse_flags,
	md_error_t	*ep
)
{
	int			rval = 0;

	if ((inuse_flags & MDCHK_MOUNTED) &&
	    (rval = meta_check_mounted(sp, np, ep)) != 0)
		return (rval);

	if ((inuse_flags & MDCHK_SWAP) &&
	    (rval = meta_check_swapped(sp, np, ep)) != 0)
		return (rval);

	if ((inuse_flags & MDCHK_DUMP) &&
	    (rval = meta_check_dump(sp, np, ep)) != 0)
		return (rval);

	return (rval);
}

int
meta_check_driveinset(mdsetname_t *sp, mddrivename_t *dn, md_error_t *ep)
{
	set_t		setno;
	set_t		max_sets;

	if ((max_sets = get_max_sets(ep)) == 0)
		return (-1);

	for (setno = 1; setno < max_sets; setno++) {
		mdsetname_t	*sp1;
		int		is_it;

		if (setno == sp->setno)
			continue;

		if ((sp1 = metasetnosetname(setno, ep)) == NULL) {
			if (mdismddberror(ep, MDE_DB_NODB)) {
				mdclrerror(ep);
				return (0);
			}
			if (mdiserror(ep, MDE_NO_SET)) {
				mdclrerror(ep);
				continue;
			}
			return (-1);
		}

		metaflushsetname(sp1);

		if ((is_it = meta_is_drive_in_thisset(sp1, dn, FALSE, ep))
		    == -1)
			return (-1);

		if (is_it)
			return (mddserror(ep, MDE_DS_DRIVEINSET, sp->setno,
			    sp1->setname, dn->cname, sp->setname));
	}

	return (0);
}

/*
 * Add a device/device id tuple to the devname cache
 */
static void
add_to_devname_list(
	char 		*device_name,		/* fully qualified dev name */
	ddi_devid_t	devid			/* device id */
)
{
	dev_list_t	*dnlp;

	dnlp = Zalloc(sizeof (*dnlp));
	dnlp->dev_name = Strdup(device_name);
	dnlp->devid = devid;

	/* link the node into the devname list */
	dnlp->dev_nxt = devnamelist;
	devnamelist = dnlp;
}

/*
 * check for same drive
 *
 * Differentiate between matching on name/dev_t and devid.  In the latter
 * case it is correct to fail but misleading to give the same error msg as
 * for an overlapping slice.
 *
 */
int
meta_check_samedrive(
	mdname_t	*np1,		/* first comp */
	mdname_t	*np2,		/* second comp */
	md_error_t	*ep
)
{

	mdcinfo_t	*cinfop1, *cinfop2;
	mdnmtype_t	type1 = np1->drivenamep->type;
	mdnmtype_t	type2 = np2->drivenamep->type;
	int		l = 0;

	char		*name1 = NULL;
	char		*name2 = NULL;

	int		retval = CANT_TELL;
	int		fd1 = -1;
	int		fd2 = -1;
	int		rc1 = -2, rc2 = -2;
	uint_t		strl1 = 0, strl2 = 0;
	int		devid1_found = 0;
	int		devid2_found = 0;

	ddi_devid_t	devid1 = NULL;
	ddi_devid_t	devid2 = NULL;
	dev_list_t	*dnlp = NULL;

	assert(type1 != MDT_FAST_META && type1 != MDT_FAST_COMP);
	assert(type2 != MDT_FAST_META && type2 != MDT_FAST_COMP);

	/*
	 * The process of determining if 2 names are the same drive is
	 * as follows:
	 *
	 * Case 1 - The filenames are identical
	 *
	 * Case 2 - Both devices have a devid
	 * 	get and compare the devids for the devices. If both
	 * 	devices have a devid then the compare will is all
	 *	that is needed we are done.
	 *
	 * Case 3 - One or more devices does not have a devid
	 *	start by doing a simple compare of the name, if they
	 *	are the same just return.
	 *
	 *	If the names differ then keep going and see if the
	 *	may be the same underlying devic.  First check to
	 *	see if the sd name is the same (old code).
	 *
	 *	Then check the major and minor numbers to see if
	 *	they are the same.  If they are then return (old code).
	 *
	 *	Next compare the raw name and the component name and
	 *	if they are the same then return.
	 *
	 *	All else has failed so use the component name (cname)
	 *	component number and unit number.  If they all are
	 *	equal then call them the same drive.
	 *
	 */

	if ((np1 == NULL) || (np2 == NULL))
		return (NOT_SAMEDRIVE);

	/* if the name structs are the same then the drives must be */
	if (np1 == np2)
		return (IDENTICAL_NAME_DEVT);

	name1 = np1->bname;
	name2 = np2->bname;

	if ((name1 == NULL) || ((strl1 = strlen(name1)) == 0) ||
	    (name2 == NULL) || ((strl2 = strlen(name2)) == 0))
		return (NOT_SAMEDRIVE);

	if ((strl1 == strl2) && (strcmp(name1, name2) == 0)) {
		/* names are identical */
		return (IDENTICAL_NAME_DEVT);
	}

	if (is_metaname(name1) || is_metaname(name2))
		return (NOT_SAMEDRIVE);

	/*
	 * Check to see if the devicename is in the static list.  If so,
	 * use its devid.  Otherwise do the expensive operations
	 * of opening the device, getting the devid, and closing the
	 * device.  Add the result into the static list.
	 *
	 * The case where this list will be useful is when there are soft
	 * partitions on multiple drives and a new soft partition is being
	 * created.  In that situation the underlying physical device name
	 * for the new soft partition would be compared against each of the
	 * existing soft partititions.  Without this static list that would
	 * involve 2 opens, closes, and devid gets for each existing soft
	 * partition
	 */
	for (dnlp = devnamelist; (dnlp != NULL) &&
	    !(devid1_found && devid2_found); dnlp = dnlp->dev_nxt) {
		if (!devid1_found && (strcmp(dnlp->dev_name, name1) == 0)) {
			devid1_found = 1;
			devid1 = dnlp->devid;
			if (devid1 == NULL)
				rc1 = 1;
			else
				rc1 = 0;
			continue;
		}
		if (!devid2_found && (strcmp(dnlp->dev_name, name2) == 0)) {
			devid2_found = 1;
			devid2 = dnlp->devid;
			if (devid2 == NULL)
				rc2 = 1;
			else
				rc2 = 0;
			continue;
		}
	}

	/*
	 * Start by checking if the device has a device id, and if they
	 * are equal.  If they are there is no question there is a match.
	 *
	 * The process here is open each disk, get the devid for each
	 * disk.  If they both have a devid compare them and return
	 * the results.
	 */
	if (!devid1_found) {
		if ((fd1 = open(name1, O_RDONLY | O_NDELAY)) < 0) {
			return (NOT_SAMEDRIVE);
		}
		rc1 = devid_get(fd1, &devid1);
		(void) close(fd1);

		/* add the name and devid to the cache */
		add_to_devname_list(name1, devid1);
	}

	if (!devid2_found) {
		if ((fd2 = open(name2, O_RDONLY | O_NDELAY)) < 0) {
			return (NOT_SAMEDRIVE);
		}
		rc2 = devid_get(fd2, &devid2);
		(void) close(fd2);

		/* add the name and devid to the cache */
		add_to_devname_list(name2, devid2);
	}


	if ((rc1 == 0) && (rc2 == 0)) {
		if (devid_compare(devid1, devid2) == 0)
			retval = IDENTICAL_DEVIDS; /* same devid */
		else
			retval = NOT_SAMEDRIVE; /* different drives */

	}

	if (retval >= 0) {
		return (retval);
	}

	/*
	 * At this point in time one of the two drives did not have a
	 * device ID.  Do not make the assumption that is one drive
	 * did have a device id and the other did not that they are not
	 * the same.  One drive could be covered by a device and still
	 * be the same drive.  This is a general flaw in the system at
	 * this time.
	 */

	/*
	 * The optimization can not happen if we are given an old style name
	 * in the form /dev/XXNN[a-h], since the name caches differently and
	 * allows overlaps to happen.
	 */
	if (! ((sscanf(np1->bname, "/dev/%*[^0-9/]%*u%*[a-h]%n", &l) == 0 &&
	    l == strlen(np1->bname)) ||
	    (sscanf(np2->bname, "/dev/%*[^0-9/]%*u%*[a-h]%n", &l) == 0 &&
	    l == strlen(np2->bname))) &&
	    ((type1 == MDT_COMP) || (type1 == MDT_META)) &&
	    ((type2 == MDT_COMP) || (type2 == MDT_META)))
		if (np1->drivenamep == np2->drivenamep)
			return (IDENTICAL_NAME_DEVT);
		else
			return (NOT_SAMEDRIVE);

	/* check for same drive */
	if (meta_getmajor(np1->dev) != meta_getmajor(np2->dev))
		return (NOT_SAMEDRIVE);		/* not same drive */

	if (((cinfop1 = metagetcinfo(np1, ep)) == NULL) ||
	    ((cinfop2 = metagetcinfo(np2, ep)) == NULL)) {
		if ((strcmp(np1->drivenamep->cname,
		    np2->drivenamep->cname) != 0) &&
		    (strcmp(np1->drivenamep->rname,
		    np2->drivenamep->rname) != 0)) {
			mdclrerror(ep);
			return (NOT_SAMEDRIVE);	/* not same drive */
		} else {
			return (CANT_TELL);	/* can't tell */
		}
	} else if ((strncmp(cinfop1->cname, cinfop2->cname,
	    sizeof (cinfop1->cname)) != 0) ||
	    (cinfop1->cnum != cinfop2->cnum) ||
	    (cinfop1->unit != cinfop2->unit)) {
		return (NOT_SAMEDRIVE);		/* not same drive */
	}

	/* same drive */
	return (IDENTICAL_NAME_DEVT);
}

/*
 * check for overlap
 */
int
meta_check_overlap(
	char		*uname,		/* user supplied name for errors */
	mdname_t	*np1,		/* first comp */
	diskaddr_t	slblk1,		/* first comp - start logical block */
	diskaddr_t	nblks1,		/* first comp - # of blocks */
	mdname_t	*np2,		/* second comp */
	diskaddr_t	slblk2,		/* second comp - start logical block */
	diskaddr_t	nblks2,		/* second comp - # of blocks */
	md_error_t	*ep
)
{
	diskaddr_t	sblk1, sblk2;
	mdvtoc_t	*vtocp1, *vtocp2;
	uint_t		partno1, partno2;
	mdpart_t	*partp1, *partp2;
	int		ret;

	/* verify args */
	if (slblk1 == MD_DISKADDR_ERROR) {
		assert(0);
		return (mdsyserror(ep, EINVAL, np1->cname));
	}
	if (slblk2 == MD_DISKADDR_ERROR) {
		assert(0);
		return (mdsyserror(ep, EINVAL, np2->cname));
	}

	/* check for same drive */
	if ((ret = meta_check_samedrive(np1, np2, ep)) == 0) {
		return (0);			/* not same drive */
	} else if (ret < 0) {
		return (-1);			/* can't tell */
	}

	/* check for overlap */
	if (((vtocp1 = metagetvtoc(np1, FALSE, &partno1, ep)) == NULL) ||
	    ((vtocp2 = metagetvtoc(np2, FALSE, &partno2, ep)) == NULL)) {
		return (-1);			/* can't tell */
	}
	partp1 = &vtocp1->parts[partno1];
	partp2 = &vtocp2->parts[partno2];
	sblk1 = partp1->start + slblk1;
	if (nblks1 == -1)
		nblks1 = partp1->size - slblk1;
	sblk2 = partp2->start + slblk2;
	if (nblks2 == -1)
		nblks2 = partp2->size - slblk2;
	if (((sblk1 >= sblk2) && (sblk1 < (sblk2 + nblks2))) ||
	    ((sblk2 >= sblk1) && (sblk2 < (sblk1 + nblks1)))) {
		if (np1->dev == np2->dev) {	/* slice in use */
			return (mduseerror(ep, MDE_ALREADY, np1->dev,
			    uname, np1->cname));
		}
		if (ret == IDENTICAL_NAME_DEVT)
			return (mduseerror(ep,		/* slice overlaps */
			    MDE_OVERLAP, np1->dev, uname, np1->cname));
		else
			return (mduseerror(ep,		/* same devid */
			    MDE_SAME_DEVID, np1->dev, uname, np2->cname));
	}

	/* return success */
	return (0);				/* no overlap */
}

/*
 * check to see if a device is in a metadevice
 */
int
meta_check_inmeta(
	mdsetname_t	*sp,
	mdname_t	*np,
	mdchkopts_t	options,
	diskaddr_t	slblk,
	diskaddr_t	nblks,
	md_error_t	*ep
)
{
	uint_t		partno;

	/* see if replica slice is ok, only applies to disks in sets */
	if (! (options & MDCHK_ALLOW_REPSLICE) &&
	    ! metaislocalset(sp)) {
		uint_t	rep_slice;

		if (metagetvtoc(np, FALSE, &partno, ep) == NULL)
			return (-1);
		if (meta_replicaslice(np->drivenamep, &rep_slice, ep)
		    != 0)
			return (-1);
		if (partno == rep_slice)
			return (mddeverror(ep, MDE_REPCOMP_INVAL, np->dev,
			    np->cname));
	}

	/* check for databases */
	if (meta_check_inreplica(sp, np, slblk, nblks, ep) != 0) {
		if (mdisuseerror(ep, MDE_ALREADY)) {
			if (options & MDCHK_ALLOW_MDDB) {
				mdclrerror(ep);
			} else {
				return (mddeverror(ep, MDE_HAS_MDDB,
				    np->dev, np->cname));
			}
		} else {
			return (-1);
		}
	}

	/* check metadevices */
	if (meta_check_instripe(sp, np, slblk, nblks, ep) != 0)
		return (-1);
	if (meta_check_inmirror(sp, np, slblk, nblks, ep) != 0)
		return (-1);
	if (meta_check_intrans(sp, np, options, slblk, nblks, ep) != 0)
		return (-1);
	if (meta_check_insp(sp, np, slblk, nblks, ep) != 0)
		return (-1);
	if (! (options & MDCHK_ALLOW_HS)) {
		if (meta_check_inhsp(sp, np, slblk, nblks, ep) != 0)
			return (-1);
	}
	if (meta_check_inraid(sp, np, slblk, nblks, ep) != 0)
		return (-1);

	/* return success */
	return (0);
}

/*
 * check to see if a device is in its set
 */
int
meta_check_inset(
	mdsetname_t	*sp,
	mdname_t	*np,
	md_error_t	*ep
)
{
	mdsetname_t	*npsp;
	int		bypass_daemon = FALSE;


	/* check devices set */
	if (metaislocalset(sp))
		bypass_daemon = TRUE;
	if ((npsp = metagetset(np, bypass_daemon, ep)) == NULL) {
		if ((! metaismeta(np)) &&
		    (metaislocalset(sp)) &&
		    (mdismddberror(ep, MDE_DB_NODB))) {
			mdclrerror(ep);
			npsp = sp;
		} else {
			return (-1);
		}
	}

	/* check set */
	if (metaissameset(sp, npsp))
		return (0);

	/* return appropriate error */
	if (metaislocalset(sp))
		return (mddeverror(ep, MDE_IN_SHARED_SET, np->dev, np->cname));
	else
		return (mddeverror(ep, MDE_NOT_IN_SET, np->dev, np->cname));
}

/*
 * check to see if current user is root
 */
int
meta_check_root(md_error_t *ep)
{
	if (geteuid() != 0) {
		(void) mderror(ep, MDE_NOPERM, "");
		return (-1);
	}
	return (0);
}