6362672 import gets confused about overlapping slices
authoreschrock
Mon, 30 Jan 2006 21:34:28 -0800
changeset 1354 81359ee1ee63
parent 1353 3b8d786cd856
child 1355 bfa8ad95acbb
6362672 import gets confused about overlapping slices 6364582 need to fixup paths if they've changed
usr/src/cmd/truss/codes.c
usr/src/cmd/zpool/zpool_main.c
usr/src/cmd/zpool/zpool_util.c
usr/src/cmd/zpool/zpool_util.h
usr/src/lib/libzfs/common/libzfs.h
usr/src/lib/libzfs/common/libzfs_import.c
usr/src/lib/libzfs/common/libzfs_pool.c
usr/src/lib/libzfs/spec/libzfs.spec
usr/src/uts/common/fs/zfs/spa.c
usr/src/uts/common/fs/zfs/sys/spa.h
usr/src/uts/common/fs/zfs/zfs_ioctl.c
usr/src/uts/common/sys/fs/zfs.h
--- a/usr/src/cmd/truss/codes.c	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/cmd/truss/codes.c	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -891,6 +891,8 @@
 		"zfs_cmd_t" },
 	{ (uint_t)ZFS_IOC_VDEV_DETACH,		"ZFS_IOC_VDEV_DETACH",
 		"zfs_cmd_t" },
+	{ (uint_t)ZFS_IOC_VDEV_SETPATH,		"ZFS_IOC_VDEV_SETPATH",
+		"zfs_cmd_t" },
 	{ (uint_t)ZFS_IOC_OBJSET_STATS,		"ZFS_IOC_OBJSET_STATS",
 		"zfs_cmd_t" },
 	{ (uint_t)ZFS_IOC_DATASET_LIST_NEXT,	"ZFS_IOC_DATASET_LIST_NEXT",
--- a/usr/src/cmd/zpool/zpool_main.c	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/cmd/zpool/zpool_main.c	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -261,7 +261,7 @@
 }
 
 void
-print_vdev_tree(const char *name, nvlist_t *nv, int indent)
+print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent)
 {
 	nvlist_t **child;
 	uint_t c, children;
@@ -275,8 +275,8 @@
 		return;
 
 	for (c = 0; c < children; c++) {
-		vname = vdev_get_name(child[c]);
-		print_vdev_tree(vname, child[c], indent + 2);
+		vname = zpool_vdev_name(zhp, child[c]);
+		print_vdev_tree(zhp, vname, child[c], indent + 2);
 		free(vname);
 	}
 }
@@ -364,8 +364,8 @@
 		(void) printf(gettext("would update '%s' to the following "
 		    "configuration:\n"), zpool_get_name(zhp));
 
-		print_vdev_tree(poolname, poolnvroot, 0);
-		print_vdev_tree(NULL, nvroot, 0);
+		print_vdev_tree(zhp, poolname, poolnvroot, 0);
+		print_vdev_tree(zhp, NULL, nvroot, 0);
 
 		ret = 0;
 	} else {
@@ -527,7 +527,7 @@
 		(void) printf(gettext("would create '%s' with the "
 		    "following layout:\n\n"), poolname);
 
-		print_vdev_tree(poolname, nvroot, 0);
+		print_vdev_tree(NULL, poolname, nvroot, 0);
 
 		ret = 0;
 	} else {
@@ -691,9 +691,9 @@
  * name column.
  */
 static int
-max_width(nvlist_t *nv, int depth, int max)
+max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
 {
-	char *name = vdev_get_name(nv);
+	char *name = zpool_vdev_name(zhp, nv);
 	nvlist_t **child;
 	uint_t c, children;
 	int ret;
@@ -708,7 +708,7 @@
 		return (max);
 
 	for (c = 0; c < children; c++)
-		if ((ret = max_width(child[c], depth + 2, max)) > max)
+		if ((ret = max_width(zhp, child[c], depth + 2, max)) > max)
 			max = ret;
 
 	return (max);
@@ -766,7 +766,7 @@
 		return;
 
 	for (c = 0; c < children; c++) {
-		vname = vdev_get_name(child[c]);
+		vname = zpool_vdev_name(NULL, child[c]);
 		print_import_config(vname, child[c],
 		    namewidth, depth + 2);
 		free(vname);
@@ -875,7 +875,7 @@
 
 	(void) printf(gettext("config:\n\n"));
 
-	namewidth = max_width(nvroot, 0, 0);
+	namewidth = max_width(NULL, nvroot, 0, 0);
 	if (namewidth < 10)
 		namewidth = 10;
 	print_import_config(name, nvroot, namewidth, 0);
@@ -1192,8 +1192,8 @@
  * is a verbose output, and we don't want to display the toplevel pool stats.
  */
 void
-print_vdev_stats(const char *name, nvlist_t *oldnv, nvlist_t *newnv,
-	iostat_cbdata_t *cb, int depth)
+print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
+    nvlist_t *newnv, iostat_cbdata_t *cb, int depth)
 {
 	nvlist_t **oldchild, **newchild;
 	uint_t c, children;
@@ -1260,8 +1260,8 @@
 		return;
 
 	for (c = 0; c < children; c++) {
-		vname = vdev_get_name(newchild[c]);
-		print_vdev_stats(vname, oldnv ? oldchild[c] : NULL,
+		vname = zpool_vdev_name(zhp, newchild[c]);
+		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
 		    newchild[c], cb, depth + 2);
 		free(vname);
 	}
@@ -1308,7 +1308,7 @@
 	/*
 	 * Print out the statistics for the pool.
 	 */
-	print_vdev_stats(zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
+	print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0);
 
 	if (cb->cb_verbose)
 		print_iostat_separator(cb);
@@ -1328,7 +1328,7 @@
 		if (!cb->cb_verbose)
 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
 		else
-			cb->cb_namewidth = max_width(nvroot, 0, 0);
+			cb->cb_namewidth = max_width(zhp, nvroot, 0, 0);
 	}
 
 	/*
@@ -2158,7 +2158,8 @@
  * Print out configuration state as requested by status_callback.
  */
 void
-print_status_config(const char *name, nvlist_t *nv, int namewidth, int depth)
+print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
+    int namewidth, int depth)
 {
 	nvlist_t **child;
 	uint_t c, children;
@@ -2214,8 +2215,8 @@
 	(void) printf("\n");
 
 	for (c = 0; c < children; c++) {
-		vname = vdev_get_name(child[c]);
-		print_status_config(vname, child[c],
+		vname = zpool_vdev_name(zhp, child[c]);
+		print_status_config(zhp, vname, child[c],
 		    namewidth, depth + 2);
 		free(vname);
 	}
@@ -2352,14 +2353,15 @@
 		(void) printf(gettext(" scrub: "));
 		print_scrub_status(nvroot);
 
-		namewidth = max_width(nvroot, 0, 0);
+		namewidth = max_width(zhp, nvroot, 0, 0);
 		if (namewidth < 10)
 			namewidth = 10;
 
 		(void) printf(gettext("config:\n\n"));
 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
-		print_status_config(zpool_get_name(zhp), nvroot, namewidth, 0);
+		print_status_config(zhp, zpool_get_name(zhp), nvroot,
+		    namewidth, 0);
 	} else {
 		(void) printf(gettext("config: The configuration cannot be "
 		    "determined.\n"));
--- a/usr/src/cmd/zpool/zpool_util.c	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/cmd/zpool/zpool_util.c	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -78,33 +78,3 @@
 	    gettext("internal error: out of memory\n"));
 	exit(1);
 }
-
-/*
- * Given a vdev, return the name to display in iostat.  If the vdev has a path,
- * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
- * We also check if this is a whole disk, in which case we strip off the
- * trailing 's0' slice name.
- */
-char *
-vdev_get_name(nvlist_t *nv)
-{
-	char *path;
-	uint64_t wholedisk;
-
-	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
-
-		if (strncmp(path, "/dev/dsk/", 9) == 0)
-			path += 9;
-
-		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
-		    &wholedisk) == 0 && wholedisk) {
-			char *tmp = safe_strdup(path);
-			tmp[strlen(path) - 2] = '\0';
-			return (tmp);
-		}
-	} else {
-		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
-	}
-
-	return (safe_strdup(path));
-}
--- a/usr/src/cmd/zpool/zpool_util.h	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/cmd/zpool/zpool_util.h	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -43,8 +43,6 @@
 char *safe_strdup(const char *);
 void no_memory(void);
 
-char *vdev_get_name(nvlist_t *nv);
-
 /*
  * Virtual device functions
  */
--- a/usr/src/lib/libzfs/common/libzfs.h	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/lib/libzfs/common/libzfs.h	Mon Jan 30 21:34:28 2006 -0800
@@ -144,6 +144,11 @@
 extern nvlist_t *zpool_find_import(int argc, char **argv);
 
 /*
+ * Miscellaneous pool functions
+ */
+extern char *zpool_vdev_name(zpool_handle_t *, nvlist_t *);
+
+/*
  * Basic handle manipulations.  These functions do not create or destroy the
  * underlying datasets, only the references to them.
  */
--- a/usr/src/lib/libzfs/common/libzfs_import.c	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/lib/libzfs/common/libzfs_import.c	Mon Jan 30 21:34:28 2006 -0800
@@ -108,6 +108,7 @@
 			devid_str_free(minor);
 		devid_free(devid);
 	}
+	(void) close(fd);
 
 	return (ret);
 }
@@ -123,8 +124,9 @@
 	nvlist_t **child;
 	uint_t c, children;
 	uint64_t guid;
-	name_entry_t *ne;
-	char *devid;
+	name_entry_t *ne, *best;
+	char *path, *devid;
+	int matched;
 
 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN,
 	    &child, &children) == 0) {
@@ -137,19 +139,55 @@
 	 * This is a leaf (file or disk) vdev.  In either case, go through
 	 * the name list and see if we find a matching guid.  If so, replace
 	 * the path and see if we can calculate a new devid.
+	 *
+	 * There may be multiple names associated with a particular guid, in
+	 * which case we have overlapping slices or multiple paths to the same
+	 * disk.  If this is the case, then we want to pick the path that is
+	 * the most similar to the original, where "most similar" is the number
+	 * of matching characters starting from the end of the path.  This will
+	 * preserve slice numbers even if the disks have been reorganized, and
+	 * will also catch preferred disk names if multiple paths exist.
 	 */
 	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &guid) == 0);
+	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0)
+		path = NULL;
 
-	for (ne = names; ne != NULL; ne = ne->ne_next)
-		if (ne->ne_guid == guid)
-			break;
+	matched = 0;
+	best = NULL;
+	for (ne = names; ne != NULL; ne = ne->ne_next) {
+		if (ne->ne_guid == guid) {
+			const char *src, *dst;
+			int count;
+
+			if (path == NULL) {
+				best = ne;
+				break;
+			}
 
-	if (ne == NULL)
+			src = ne->ne_name + strlen(ne->ne_name) - 1;
+			dst = path + strlen(path) - 1;
+			for (count = 0; src >= ne->ne_name && dst >= path;
+			    src--, dst--, count++)
+				if (*src != *dst)
+					break;
+
+			/*
+			 * At this point, 'count' is the number of characters
+			 * matched from the end.
+			 */
+			if (count > matched || best == NULL) {
+				best = ne;
+				matched = count;
+			}
+		}
+	}
+
+	if (best == NULL)
 		return;
 
-	verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, ne->ne_name) == 0);
+	verify(nvlist_add_string(nv, ZPOOL_CONFIG_PATH, best->ne_name) == 0);
 
-	if ((devid = get_devid(ne->ne_name)) == NULL) {
+	if ((devid = get_devid(best->ne_name)) == NULL) {
 		(void) nvlist_remove_all(nv, ZPOOL_CONFIG_DEVID);
 	} else {
 		verify(nvlist_add_string(nv, ZPOOL_CONFIG_DEVID, devid) == 0);
--- a/usr/src/lib/libzfs/common/libzfs_pool.c	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1150,3 +1150,145 @@
 	zfs_close(zfp);
 	return (ret);
 }
+
+/*
+ * Convert from a devid string to a path.
+ */
+static char *
+devid_to_path(char *devid_str)
+{
+	ddi_devid_t devid;
+	char *minor;
+	char *path;
+	devid_nmlist_t *list = NULL;
+	int ret;
+
+	if (devid_str_decode(devid_str, &devid, &minor) != 0)
+		return (NULL);
+
+	ret = devid_deviceid_to_nmlist("/dev", devid, minor, &list);
+
+	devid_str_free(minor);
+	devid_free(devid);
+
+	if (ret != 0)
+		return (NULL);
+
+	path = zfs_strdup(list[0].devname);
+	devid_free_nmlist(list);
+
+	return (path);
+}
+
+/*
+ * Convert from a path to a devid string.
+ */
+static char *
+path_to_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);
+}
+
+/*
+ * Issue the necessary ioctl() to update the stored path value for the vdev.  We
+ * ignore any failure here, since a common case is for an unprivileged user to
+ * type 'zpool status', and we'll display the correct information anyway.
+ */
+static void
+set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
+{
+	zfs_cmd_t zc = { 0 };
+
+	(void) strncpy(zc.zc_name, zhp->zpool_name, sizeof (zc.zc_name));
+	(void) strncpy(zc.zc_prop_value, path, sizeof (zc.zc_prop_value));
+	verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
+	    &zc.zc_pool_guid) == 0);
+
+	(void) ioctl(zfs_fd, ZFS_IOC_VDEV_SETPATH, &zc);
+}
+
+/*
+ * Given a vdev, return the name to display in iostat.  If the vdev has a path,
+ * we use that, stripping off any leading "/dev/dsk/"; if not, we use the type.
+ * We also check if this is a whole disk, in which case we strip off the
+ * trailing 's0' slice name.
+ *
+ * This routine is also responsible for identifying when disks have been
+ * reconfigured in a new location.  The kernel will have opened the device by
+ * devid, but the path will still refer to the old location.  To catch this, we
+ * first do a path -> devid translation (which is fast for the common case).  If
+ * the devid matches, we're done.  If not, we do a reverse devid -> path
+ * translation and issue the appropriate ioctl() to update the path of the vdev.
+ * If 'zhp' is NULL, then this is an exported pool, and we don't need to do any
+ * of these checks.
+ */
+char *
+zpool_vdev_name(zpool_handle_t *zhp, nvlist_t *nv)
+{
+	char *path, *devid;
+	uint64_t wholedisk;
+
+	if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
+
+		if (zhp != NULL &&
+		    nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
+			/*
+			 * Determine if the current path is correct.
+			 */
+			char *newdevid = path_to_devid(path);
+
+			if (newdevid == NULL ||
+			    strcmp(devid, newdevid) != 0) {
+				char *newpath;
+
+				if ((newpath = devid_to_path(devid)) != NULL) {
+					/*
+					 * Update the path appropriately.
+					 */
+					set_path(zhp, nv, newpath);
+					verify(nvlist_add_string(nv,
+					    ZPOOL_CONFIG_PATH, newpath) == 0);
+					free(newpath);
+					verify(nvlist_lookup_string(nv,
+					    ZPOOL_CONFIG_PATH, &path) == 0);
+				}
+
+				if (newdevid)
+					devid_str_free(newdevid);
+			}
+
+		}
+
+		if (strncmp(path, "/dev/dsk/", 9) == 0)
+			path += 9;
+
+		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
+		    &wholedisk) == 0 && wholedisk) {
+			char *tmp = zfs_strdup(path);
+			tmp[strlen(path) - 2] = '\0';
+			return (tmp);
+		}
+	} else {
+		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &path) == 0);
+	}
+
+	return (zfs_strdup(path));
+}
--- a/usr/src/lib/libzfs/spec/libzfs.spec	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/lib/libzfs/spec/libzfs.spec	Mon Jan 30 21:34:28 2006 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 # CDDL HEADER START
@@ -335,3 +335,7 @@
 function zpool_vdev_detach
 version SUNWprivate_1.1
 end
+
+function zpool_vdev_name
+version  SUNWprivate_1.1
+end
--- a/usr/src/uts/common/fs/zfs/spa.c	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/spa.c	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1202,6 +1202,33 @@
 }
 
 /*
+ * Update the stored path for this vdev.  Dirty the vdev configuration, relying
+ * on spa_vdev_enter/exit() to synchronize the labels and cache.
+ */
+int
+spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath)
+{
+	vdev_t *rvd, *vd;
+	uint64_t txg;
+
+	rvd = spa->spa_root_vdev;
+
+	txg = spa_vdev_enter(spa);
+
+	if ((vd = vdev_lookup_by_guid(rvd, guid)) == NULL)
+		return (spa_vdev_exit(spa, NULL, txg, ENOENT));
+
+	spa_strfree(vd->vdev_path);
+	vd->vdev_path = spa_strdup(newpath);
+
+	spa_config_set(spa, spa_config_generate(spa, rvd, txg, 0));
+
+	vdev_config_dirty(vd->vdev_top);
+
+	return (spa_vdev_exit(spa, NULL, txg, 0));
+}
+
+/*
  * ==========================================================================
  * SPA Scrubbing
  * ==========================================================================
--- a/usr/src/uts/common/fs/zfs/sys/spa.h	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -307,6 +307,7 @@
 extern int spa_vdev_detach(spa_t *spa, const char *path, uint64_t guid,
     int replace_done);
 extern void spa_vdev_replace_done(spa_t *spa);
+extern int spa_vdev_setpath(spa_t *spa, uint64_t guid, const char *newpath);
 
 /* scrubbing */
 extern int spa_scrub(spa_t *spa, pool_scrub_type_t type, boolean_t force);
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Mon Jan 30 21:34:28 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -621,6 +621,25 @@
 }
 
 static int
+zfs_ioc_vdev_setpath(zfs_cmd_t *zc)
+{
+	spa_t *spa;
+	char *path = zc->zc_prop_value;
+	uint64_t guid = zc->zc_pool_guid;
+	int error;
+
+	error = spa_open(zc->zc_name, &spa, FTAG);
+	if (error != 0)
+		return (error);
+
+	error = spa_vdev_setpath(spa, guid, path);
+
+	spa_close(spa, FTAG);
+	return (error);
+}
+
+
+static int
 zfs_get_stats(zfs_cmd_t *zc)
 {
 	char *name = zc->zc_name;
@@ -1075,6 +1094,7 @@
 	{ zfs_ioc_vdev_offline,		zfs_secpolicy_config,	pool_name },
 	{ zfs_ioc_vdev_attach,		zfs_secpolicy_config,	pool_name },
 	{ zfs_ioc_vdev_detach,		zfs_secpolicy_config,	pool_name },
+	{ zfs_ioc_vdev_setpath,		zfs_secpolicy_config,	pool_name },
 	{ zfs_ioc_objset_stats,		zfs_secpolicy_read,	dataset_name },
 	{ zfs_ioc_dataset_list_next,	zfs_secpolicy_read,	dataset_name },
 	{ zfs_ioc_snapshot_list_next,	zfs_secpolicy_read,	dataset_name },
--- a/usr/src/uts/common/sys/fs/zfs.h	Mon Jan 30 18:57:13 2006 -0800
+++ b/usr/src/uts/common/sys/fs/zfs.h	Mon Jan 30 21:34:28 2006 -0800
@@ -285,6 +285,7 @@
 	ZFS_IOC_VDEV_OFFLINE,
 	ZFS_IOC_VDEV_ATTACH,
 	ZFS_IOC_VDEV_DETACH,
+	ZFS_IOC_VDEV_SETPATH,
 	ZFS_IOC_OBJSET_STATS,
 	ZFS_IOC_DATASET_LIST_NEXT,
 	ZFS_IOC_SNAPSHOT_LIST_NEXT,