diff options
author | Joshua M. Clulow <josh@sysmgr.org> | 2019-08-28 16:57:58 -0700 |
---|---|---|
committer | Joshua M. Clulow <josh@sysmgr.org> | 2019-08-28 16:57:58 -0700 |
commit | 727feae5cc0661f4ec44e87b934863693bedf87d (patch) | |
tree | 615587ac0f02f7ddcae20fcb3fca3ee3a5b4b3da | |
parent | 093e84535f35ec94776a855ada3dac96daf5d602 (diff) | |
download | illumos-joyent-727feae5cc0661f4ec44e87b934863693bedf87d.tar.gz |
10622 ZFS should still check paths for devices that have no devid
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Andy Fiddaman <omnios@citrus-it.co.uk>
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/lib/libzfs/Makefile.com | 4 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_impl.h | 3 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 136 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_util.c | 6 |
4 files changed, 120 insertions, 29 deletions
diff --git a/usr/src/lib/libzfs/Makefile.com b/usr/src/lib/libzfs/Makefile.com index 355923acae..577fa2fbca 100644 --- a/usr/src/lib/libzfs/Makefile.com +++ b/usr/src/lib/libzfs/Makefile.com @@ -22,7 +22,7 @@ # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com> # Copyright (c) 2011, 2017 by Delphix. All rights reserved. -# Copyright (c) 2018, Joyent, Inc. +# Copyright 2019 Joyent, Inc. # LIBRARY= libzfs.a @@ -74,7 +74,7 @@ CSTD= $(CSTD_GNU99) C99LMODE= -Xc99=%all LDLIBS += -lc -lm -ldevid -lgen -lnvpair -luutil -lavl -lefi \ -ladm -lidmap -ltsol -lcryptoutil -lpkcs11 -lmd -lumem -lzfs_core \ - -lcmdutils + -lcmdutils -ldevinfo CPPFLAGS += $(INCS) -D_LARGEFILE64_SOURCE=1 -D_REENTRANT $(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG diff --git a/usr/src/lib/libzfs/common/libzfs_impl.h b/usr/src/lib/libzfs/common/libzfs_impl.h index 9f9890fe58..ed5d491b0a 100644 --- a/usr/src/lib/libzfs/common/libzfs_impl.h +++ b/usr/src/lib/libzfs/common/libzfs_impl.h @@ -23,6 +23,7 @@ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 Pawel Jakub Dawidek. All rights reserved. * Copyright (c) 2011, 2017 by Delphix. All rights reserved. + * Copyright 2019 Joyent, Inc. */ #ifndef _LIBZFS_IMPL_H @@ -39,6 +40,7 @@ #include <libzfs.h> #include <libshare.h> #include <libzfs_core.h> +#include <libdevinfo.h> #include <fm/libtopo.h> @@ -88,6 +90,7 @@ struct libzfs_handle { libzfs_fru_t *libzfs_fru_list; char libzfs_chassis_id[256]; boolean_t libzfs_prop_debug; + di_devlink_handle_t libzfs_devlink; }; struct zfs_handle { diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index 8d0569dc02..c6dd8aaab6 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -3686,6 +3686,76 @@ path_to_devid(const char *path) return (ret); } +struct path_from_physpath_walker_args { + char *pfpwa_path; +}; + +/* + * Walker for use with di_devlink_walk(). Stores the "/dev" path of the first + * primary devlink (i.e., the first devlink which refers to our "/devices" + * node) and stops walking. + */ +static int +path_from_physpath_walker(di_devlink_t devlink, void *arg) +{ + struct path_from_physpath_walker_args *pfpwa = arg; + + if (di_devlink_type(devlink) != DI_PRIMARY_LINK) { + return (DI_WALK_CONTINUE); + } + + verify(pfpwa->pfpwa_path == NULL); + if ((pfpwa->pfpwa_path = strdup(di_devlink_path(devlink))) != NULL) { + return (DI_WALK_TERMINATE); + } + + return (DI_WALK_CONTINUE); +} + +/* + * Search for a "/dev" path that refers to our physical path. Returns the new + * path if one is found and it does not match the existing "path" value. If + * the value is unchanged, or one could not be found, returns NULL. + */ +static char * +path_from_physpath(libzfs_handle_t *hdl, const char *path, + const char *physpath) +{ + struct path_from_physpath_walker_args pfpwa; + + if (physpath == NULL) { + return (NULL); + } + + if (hdl->libzfs_devlink == NULL) { + if ((hdl->libzfs_devlink = di_devlink_init(NULL, 0)) == + DI_LINK_NIL) { + /* + * We may not be able to open a handle if this process + * is insufficiently privileged, or we are too early in + * boot for devfsadm to be ready. Ignore this error + * and defer the path check to a subsequent run. + */ + return (NULL); + } + } + + pfpwa.pfpwa_path = NULL; + (void) di_devlink_walk(hdl->libzfs_devlink, NULL, physpath, + DI_PRIMARY_LINK, &pfpwa, path_from_physpath_walker); + + if (path != NULL && pfpwa.pfpwa_path != NULL && + strcmp(path, pfpwa.pfpwa_path) == 0) { + /* + * If the path is already correct, no change is required. + */ + free(pfpwa.pfpwa_path); + return (NULL); + } + + return (pfpwa.pfpwa_path); +} + /* * 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 @@ -3723,11 +3793,9 @@ char * zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, int name_flags) { - char *path, *devid, *env; + char *path, *env; uint64_t value; char buf[64]; - vdev_stat_t *vs; - uint_t vsc; env = getenv("ZPOOL_VDEV_NAME_PATH"); if (env && (strtoul(env, NULL, 0) > 0 || @@ -3750,6 +3818,11 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, (void) snprintf(buf, sizeof (buf), "%llu", (u_longlong_t)value); path = buf; } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) { + vdev_stat_t *vs; + uint_t vsc; + char *newpath = NULL; + char *physpath = NULL; + char *devid = NULL; /* * If the device is dead (faulted, offline, etc) then don't @@ -3757,36 +3830,48 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, * open a misbehaving device, which can have undesirable * effects. */ - if ((nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, + if (nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS, (uint64_t **)&vs, &vsc) != 0 || - vs->vs_state >= VDEV_STATE_DEGRADED) && - zhp != NULL && - nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { + vs->vs_state < VDEV_STATE_DEGRADED || + zhp == NULL) { + goto after_open; + } + + if (nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) { /* - * Determine if the current path is correct. + * This vdev has a devid. We can use it to check the + * current path. */ 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); - if (nvlist_add_string(nv, - ZPOOL_CONFIG_PATH, newpath) == 0) - verify(nvlist_lookup_string(nv, - ZPOOL_CONFIG_PATH, - &path) == 0); - free(newpath); - } + if (newdevid == NULL || strcmp(devid, newdevid) != 0) { + newpath = devid_to_path(devid); } - if (newdevid) + if (newdevid != NULL) devid_str_free(newdevid); + + } else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PHYS_PATH, + &physpath) == 0) { + /* + * This vdev does not have a devid, but it does have a + * physical path. Attempt to translate this to a /dev + * path. + */ + newpath = path_from_physpath(hdl, path, physpath); + } + + if (newpath != NULL) { + /* + * Update the path appropriately. + */ + set_path(zhp, nv, newpath); + if (nvlist_add_string(nv, ZPOOL_CONFIG_PATH, + newpath) == 0) { + verify(nvlist_lookup_string(nv, + ZPOOL_CONFIG_PATH, &path) == 0); + } + free(newpath); } if (name_flags & VDEV_NAME_FOLLOW_LINKS) { @@ -3798,6 +3883,7 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv, } } +after_open: if (strncmp(path, ZFS_DISK_ROOTD, strlen(ZFS_DISK_ROOTD)) == 0) path += strlen(ZFS_DISK_ROOTD); diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c index c5415b2ade..696a9e10d0 100644 --- a/usr/src/lib/libzfs/common/libzfs_util.c +++ b/usr/src/lib/libzfs/common/libzfs_util.c @@ -684,10 +684,12 @@ void libzfs_fini(libzfs_handle_t *hdl) { (void) close(hdl->libzfs_fd); - if (hdl->libzfs_mnttab) + if (hdl->libzfs_mnttab != NULL) (void) fclose(hdl->libzfs_mnttab); - if (hdl->libzfs_sharetab) + if (hdl->libzfs_sharetab != NULL) (void) fclose(hdl->libzfs_sharetab); + if (hdl->libzfs_devlink != NULL) + (void) di_devlink_fini(&hdl->libzfs_devlink); zfs_uninit_libshare(hdl); zpool_free_handles(hdl); libzfs_fru_clear(hdl, B_TRUE); |