コード例 #1
0
/*
 * handle case where device has been probed but its target driver is not
 * attached so enumeration has not quite finished. Opening the /devices
 * pathname will force the kernel to finish the enumeration process and
 * let us get the data we need.
 */
static void
get_devid(di_node_t node, ddi_devid_t *thisdevid)
{
	int fd;
	char realpath[MAXPATHLEN];
	char *openpath = di_devfs_path(node);

	errno = 0;
	bzero(realpath, MAXPATHLEN);
	if (strstr(openpath, "/devices") == NULL) {
		(void) snprintf(realpath, MAXPATHLEN,
		    "/devices%s:c,raw", openpath);
		fd = open(realpath, O_RDONLY|O_NDELAY);
	} else {
		fd = open(openpath, O_RDONLY|O_NDELAY);
	}

	if (fd < 0) {
		logmsg(MSG_INFO, "Unable to open path %s: %s\n",
		    openpath, strerror(errno));
		return;
	}

	if (devid_get(fd, thisdevid) != 0) {
		logmsg(MSG_INFO,
		    "'%s' node (%s) without a devid registered\n",
		    di_driver_name(node), di_devfs_path(node));
	}
	(void) close(fd);
}
コード例 #2
0
/*
 * Given a /devices path, lookup the corresponding devid for each minor node,
 * and find any vdevs with matching devids.  Doing this straight up would be
 * rather inefficient, O(minor nodes * vdevs in system), so we take advantage of
 * the fact that each devid ends with "/<minornode>".  Once we find any valid
 * minor node, we chop off the portion after the last slash, and then search for
 * matching vdevs, which is O(vdevs in system).
 */
static boolean_t
devid_iter(const char *devpath, zfs_process_func_t func, boolean_t wholedisk)
{
	size_t len = strlen(devpath) + sizeof ("/devices") +
	    sizeof (PHYS_PATH) - 1;
	char *fullpath;
	int fd;
	ddi_devid_t devid;
	char *devidstr, *fulldevid;
	dev_data_t data = { 0 };

	/*
	 * Try to open a known minor node.
	 */
	fullpath = alloca(len);
	(void) snprintf(fullpath, len, "/devices%s%s", devpath, PHYS_PATH);
	if ((fd = open(fullpath, O_RDONLY)) < 0)
		return (B_FALSE);

	/*
	 * Determine the devid as a string, with no trailing slash for the minor
	 * node.
	 */
	if (devid_get(fd, &devid) != 0) {
		(void) close(fd);
		return (B_FALSE);
	}
	(void) close(fd);

	if ((devidstr = devid_str_encode(devid, NULL)) == NULL) {
		devid_free(devid);
		return (B_FALSE);
	}

	len = strlen(devidstr) + 2;
	fulldevid = alloca(len);
	(void) snprintf(fulldevid, len, "%s/", devidstr);

	data.dd_compare = fulldevid;
	data.dd_func = func;
	data.dd_prop = ZPOOL_CONFIG_DEVID;
	data.dd_found = B_FALSE;
	data.dd_isdisk = wholedisk;

	(void) zpool_iter(g_zfshdl, zfs_iter_pool, &data);

	devid_str_free(devidstr);
	devid_free(devid);

	return (data.dd_found);
}
コード例 #3
0
ファイル: libzfs_import.c プロジェクト: cbreak-black/zfs
static char *
get_devid(const char *path)
{
	int fd;
	ddi_devid_t devid;
	char *minor, *ret;

	if ((fd = open(path, O_RDONLY)) < 0)
		return (NULL);

	minor = NULL;
	ret = NULL;
	if (devid_get(fd, &devid) == 0) {
		if (devid_get_minor_name(fd, &minor) == 0)
			ret = devid_str_encode(devid, minor);
		if (minor != NULL)
			devid_str_free(minor);
		devid_free(devid);
	}
	(void) close(fd);

	return (ret);
}
コード例 #4
0
ファイル: meta_check.c プロジェクト: apprisi/illumos-gate
/*
 * 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);
}
コード例 #5
0
ファイル: slice.c プロジェクト: pcd1193182/openzfs
static int
get_attrs(descriptor_t *dp, int fd,  nvlist_t *attrs)
{
	struct dk_minfo	minfo;
	int		status;
	int		data_format = FMT_UNKNOWN;
	int		snum = -1;
	int		error;
	struct extvtoc	vtoc;
	struct dk_gpt	*efip;
	struct dk_cinfo	dkinfo;
	int		cooked_fd;
	struct stat	buf;

	if (fd < 0) {
	    return (ENODEV);
	}

	/* First make sure media is inserted and spun up. */
	if (!media_read_info(fd, &minfo)) {
	    return (ENODEV);
	}

	if ((status = read_extvtoc(fd, &vtoc)) >= 0) {
	    data_format = FMT_VTOC;
	} else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) {
	    data_format = FMT_EFI;
	    if (nvlist_add_boolean(attrs, DM_EFI) != 0) {
		efi_free(efip);
		return (ENOMEM);
	    }
	}

	if (data_format == FMT_UNKNOWN) {
	    return (ENODEV);
	}

	if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) {
	    snum = dkinfo.dki_partition;
	}

	/* check the slice */
	if (data_format == FMT_VTOC) {
	    if (snum < 0 || snum >= vtoc.v_nparts ||
		vtoc.v_part[snum].p_size == 0) {
		return (ENODEV);
	    }
	} else { /* data_format == FMT_EFI */
	    if (snum < 0 || snum >= efip->efi_nparts ||
		efip->efi_parts[snum].p_size == 0) {
		efi_free(efip);
		return (ENODEV);
	    }
	}

	/* the slice exists */

	if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) {
	    if (data_format == FMT_EFI) {
		efi_free(efip);
	    }
	    return (ENOMEM);
	}

	if (data_format == FMT_VTOC) {
	    if (nvlist_add_uint64(attrs, DM_START, vtoc.v_part[snum].p_start)
		!= 0) {
		return (ENOMEM);
	    }

	    if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size)
		!= 0) {
		return (ENOMEM);
	    }

	    if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag)
		!= 0) {
		return (ENOMEM);
	    }

	    if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag)
		!= 0) {
		return (ENOMEM);
	    }

	} else { /* data_format == FMT_EFI */
	    if (nvlist_add_uint64(attrs, DM_START,
		efip->efi_parts[snum].p_start) != 0) {
		efi_free(efip);
		return (ENOMEM);
	    }

	    if (nvlist_add_uint64(attrs, DM_SIZE, efip->efi_parts[snum].p_size)
		!= 0) {
		efi_free(efip);
		return (ENOMEM);
	    }

	    if (efip->efi_parts[snum].p_name[0] != 0) {
		char	label[EFI_PART_NAME_LEN + 1];

		(void) snprintf(label, sizeof (label), "%.*s",
		    EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name);
		if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) {
		    efi_free(efip);
		    return (ENOMEM);
		}
	    }
	}

	if (data_format == FMT_EFI) {
	    efi_free(efip);
	}

	if (inuse_mnt(dp->name, attrs, &error)) {
	    if (error != 0)
		return (error);
	}

	if (fstat(fd, &buf) != -1) {
	    if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) {
		return (ENOMEM);
	    }
	}

	/*
	 * We need to open the cooked slice (not the raw one) to get the
	 * correct devid.
	 */
	cooked_fd = open(dp->name, O_RDONLY|O_NDELAY);

	if (cooked_fd >= 0) {
	    int		no_mem = 0;
	    ddi_devid_t	devid;

	    if (devid_get(cooked_fd, &devid) == 0) {
		char	*minor;

		if (devid_get_minor_name(cooked_fd, &minor) == 0) {
		    char	*devidstr;

		    if ((devidstr = devid_str_encode(devid, minor)) != 0) {

			if (nvlist_add_string(attrs, DM_DEVICEID, devidstr)
			    != 0) {
			    no_mem = 1;
			}

			devid_str_free(devidstr);
		    }
		    devid_str_free(minor);
		}
		devid_free(devid);
	    }
	    (void) close(cooked_fd);

	    if (no_mem) {
		return (ENOMEM);
	    }
	}

	return (0);
}
コード例 #6
0
/*
 * Create a leaf vdev.  Determine if this is a file or a device.  If it's a
 * device, fill in the device id to make a complete nvlist.  Valid forms for a
 * leaf vdev are:
 *
 * 	/dev/dsk/xxx	Complete disk path
 * 	/xxx		Full path to file
 * 	xxx		Shorthand for /dev/dsk/xxx
 */
nvlist_t *
make_leaf_vdev(const char *arg)
{
	char path[MAXPATHLEN];
	struct stat statbuf;
	nvlist_t *vdev = NULL;
	char *type = NULL;
	boolean_t wholedisk = B_FALSE;

	/*
	 * Determine what type of vdev this is, and put the full path into
	 * 'path'.  We detect whether this is a device of file afterwards by
	 * checking the st_mode of the file.
	 */
	if (arg[0] == '/') {
		/*
		 * Complete device or file path.  Exact type is determined by
		 * examining the file descriptor afterwards.
		 */
		if (is_whole_disk(arg, &statbuf)) {
			wholedisk = B_TRUE;
		} else if (stat(arg, &statbuf) != 0) {
			(void) fprintf(stderr,
			    gettext("cannot open '%s': %s\n"),
			    arg, strerror(errno));
			return (NULL);
		}

		(void) strlcpy(path, arg, sizeof (path));
	} else {
		/*
		 * This may be a short path for a device, or it could be total
		 * gibberish.  Check to see if it's a known device in
		 * /dev/dsk/.  As part of this check, see if we've been given a
		 * an entire disk (minus the slice number).
		 */
		(void) snprintf(path, sizeof (path), "%s/%s", DISK_ROOT,
		    arg);
		if (is_whole_disk(path, &statbuf)) {
			wholedisk = B_TRUE;
		} else if (stat(path, &statbuf) != 0) {
			/*
			 * If we got ENOENT, then the user gave us
			 * gibberish, so try to direct them with a
			 * reasonable error message.  Otherwise,
			 * regurgitate strerror() since it's the best we
			 * can do.
			 */
			if (errno == ENOENT) {
				(void) fprintf(stderr,
				    gettext("cannot open '%s': no such "
				    "device in %s\n"), arg, DISK_ROOT);
				(void) fprintf(stderr,
				    gettext("must be a full path or "
				    "shorthand device name\n"));
				return (NULL);
			} else {
				(void) fprintf(stderr,
				    gettext("cannot open '%s': %s\n"),
				    path, strerror(errno));
				return (NULL);
			}
		}
	}

	/*
	 * Determine whether this is a device or a file.
	 */
	if (S_ISBLK(statbuf.st_mode)) {
		type = VDEV_TYPE_DISK;
	} else if (S_ISREG(statbuf.st_mode)) {
		type = VDEV_TYPE_FILE;
	} else {
		(void) fprintf(stderr, gettext("cannot use '%s': must be a "
		    "block device or regular file\n"), path);
		return (NULL);
	}

	/*
	 * Finally, we have the complete device or file, and we know that it is
	 * acceptable to use.  Construct the nvlist to describe this vdev.  All
	 * vdevs have a 'path' element, and devices also have a 'devid' element.
	 */
	verify(nvlist_alloc(&vdev, NV_UNIQUE_NAME, 0) == 0);
	verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
	verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
	if (strcmp(type, VDEV_TYPE_DISK) == 0)
		verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
		    (uint64_t)wholedisk) == 0);

	/*
	 * For a whole disk, defer getting its devid until after labeling it.
	 */
	if (S_ISBLK(statbuf.st_mode) && !wholedisk) {
		/*
		 * Get the devid for the device.
		 */
		int fd;
		ddi_devid_t devid;
		char *minor = NULL, *devid_str = NULL;

		if ((fd = open(path, O_RDONLY)) < 0) {
			(void) fprintf(stderr, gettext("cannot open '%s': "
			    "%s\n"), path, strerror(errno));
			nvlist_free(vdev);
			return (NULL);
		}

		if (devid_get(fd, &devid) == 0) {
			if (devid_get_minor_name(fd, &minor) == 0 &&
			    (devid_str = devid_str_encode(devid, minor)) !=
			    NULL) {
				verify(nvlist_add_string(vdev,
				    ZPOOL_CONFIG_DEVID, devid_str) == 0);
			}
			if (devid_str != NULL)
				devid_str_free(devid_str);
			if (minor != NULL)
				devid_str_free(minor);
			devid_free(devid);
		}

		(void) close(fd);
	}

	return (vdev);
}