Example #1
0
/*
 * Check if we have the drive in our list, based upon the device id.
 * We got the device id from the dev tree walk.  This is encoded
 * using devid_str_encode(3DEVID).   In order to check the device ids we need
 * to use the devid_compare(3DEVID) function, so we need to decode the
 * string representation of the device id.
 */
descriptor_t *
drive_get_descriptor_by_name(char *name, int *errp)
{
	ddi_devid_t	devid;
	descriptor_t	**drives;
	descriptor_t	*drive = NULL;
	int		i;

	if (name == NULL || devid_str_decode(name, &devid, NULL) != 0) {
	    *errp = EINVAL;
	    return (NULL);
	}

	drives = cache_get_descriptors(DM_DRIVE, errp);
	if (*errp != 0) {
	    devid_free(devid);
	    return (NULL);
	}

	/*
	 * We have to loop through all of them, freeing the ones we don't
	 * want.  Once drive is set, we don't need to compare any more.
	 */
	for (i = 0; drives[i]; i++) {
	    if (drive == NULL && drives[i]->p.disk->devid != NULL &&
		devid_compare(devid, drives[i]->p.disk->devid) == 0) {
		drive = drives[i];

	    } else {
		/* clean up the unused descriptor */
		cache_free_descriptor(drives[i]);
	    }
	}
	free(drives);
	devid_free(devid);

	if (drive == NULL) {
	    *errp = ENODEV;
	}

	return (drive);
}
Example #2
0
/*
 * Check if we have the drive in our list, based upon the device id.
 * We got the device id from the dev tree walk.  This is encoded
 * using devid_str_encode(3DEVID).   In order to check the device ids we need
 * to use the devid_compare(3DEVID) function, so we need to decode the
 * string representation of the device id.
 */
static disk_t *
get_disk_by_deviceid(disk_t *listp, char *devidstr)
{
	ddi_devid_t	devid;

	if (devidstr == NULL || devid_str_decode(devidstr, &devid, NULL) != 0) {
		return (NULL);
	}

	while (listp != NULL) {
		if (listp->devid != NULL &&
		    devid_compare(listp->devid, devid) == 0) {
			break;
		}
		listp = listp->next;
	}

	devid_free(devid);
	return (listp);
}
Example #3
0
/*
 * 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);
}