summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs/common/libzfs_import.c
diff options
context:
space:
mode:
authoreschrock <none@none>2006-01-30 21:34:28 -0800
committereschrock <none@none>2006-01-30 21:34:28 -0800
commitc67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07 (patch)
treec677def7879e53aed9cc2dd748194594ce86aaea /usr/src/lib/libzfs/common/libzfs_import.c
parent6a0b2badb8e0f78966c154a45bd14bf3069c1486 (diff)
downloadillumos-joyent-c67d9675bbc8392fe45f3a7dfbda1ad4daa1eb07.tar.gz
6362672 import gets confused about overlapping slices
6364582 need to fixup paths if they've changed
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_import.c')
-rw-r--r--usr/src/lib/libzfs/common/libzfs_import.c54
1 files changed, 46 insertions, 8 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_import.c b/usr/src/lib/libzfs/common/libzfs_import.c
index 6c56a1a2da..cc86292a50 100644
--- a/usr/src/lib/libzfs/common/libzfs_import.c
+++ b/usr/src/lib/libzfs/common/libzfs_import.c
@@ -108,6 +108,7 @@ get_devid(const char *path)
devid_str_free(minor);
devid_free(devid);
}
+ (void) close(fd);
return (ret);
}
@@ -123,8 +124,9 @@ fix_paths(nvlist_t *nv, name_entry_t *names)
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 @@ fix_paths(nvlist_t *nv, name_entry_t *names)
* 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;
+
+ 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;
+ }
- for (ne = names; ne != NULL; ne = ne->ne_next)
- if (ne->ne_guid == guid)
- break;
+ 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 (ne == NULL)
+ 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);