summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua M. Clulow <josh@sysmgr.org>2022-11-08 12:54:43 -0800
committerJoshua M. Clulow <josh@sysmgr.org>2022-11-08 12:54:43 -0800
commitb4fb003914e70b41d96dec8011864f6af1faf3ef (patch)
treef64867f9ae24b071f386b0c2fe24a47bd97bce79
parent77c0a660417a046bfab6c8ef58d00c181c0264b3 (diff)
downloadillumos-joyent-b4fb003914e70b41d96dec8011864f6af1faf3ef.tar.gz
14978 ZFS autoexpand property should work for root pools
Reviewed by: Andy Fiddaman <illumos@fiddaman.net> Reviewed by: Toomas Soome <tsoome@me.com> Approved by: Dan McDonald <danmcd@mnx.io>
-rw-r--r--usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c8
-rw-r--r--usr/src/lib/libzfs/common/libzfs.h2
-rw-r--r--usr/src/lib/libzfs/common/libzfs_pool.c115
-rw-r--r--usr/src/lib/libzfs/common/mapfile-vers1
-rw-r--r--usr/src/lib/libzpool/Makefile.com2
-rw-r--r--usr/src/uts/common/fs/zfs/spa.c16
-rw-r--r--usr/src/uts/common/fs/zfs/spa_misc.c42
-rw-r--r--usr/src/uts/common/fs/zfs/sys/spa.h1
-rw-r--r--usr/src/uts/common/fs/zfs/zvol.c10
9 files changed, 132 insertions, 65 deletions
diff --git a/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c b/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
index 82c296a669..6a25af90f9 100644
--- a/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
+++ b/usr/src/cmd/syseventd/modules/zfs_mod/zfs_mod.c
@@ -23,6 +23,7 @@
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright 2016 Nexenta Systems, Inc. All rights reserved.
* Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -564,6 +565,13 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
char *path, fullpath[MAXPATHLEN];
uint64_t wholedisk = 0ULL;
+ /*
+ * If the /dev path of the device is invalid because the disk
+ * has been moved to a new location, we need to try to refresh
+ * that path before onlining the device.
+ */
+ zpool_vdev_refresh_path(g_zfshdl, zhp, tgt);
+
verify(nvlist_lookup_string(tgt, ZPOOL_CONFIG_PATH,
&path) == 0);
verify(nvlist_lookup_uint64(tgt, ZPOOL_CONFIG_WHOLE_DISK,
diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h
index 0516845d24..df89daf19a 100644
--- a/usr/src/lib/libzfs/common/libzfs.h
+++ b/usr/src/lib/libzfs/common/libzfs.h
@@ -316,6 +316,8 @@ extern nvlist_t *zpool_find_vdev_by_physpath(zpool_handle_t *, const char *,
boolean_t *, boolean_t *, boolean_t *);
extern int zpool_label_disk(libzfs_handle_t *, zpool_handle_t *, const char *,
zpool_boot_label_t, uint64_t, int *);
+extern void zpool_vdev_refresh_path(libzfs_handle_t *, zpool_handle_t *,
+ nvlist_t *);
/*
* Functions to manage pool properties
diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c
index 6e634a81cb..6f072e4935 100644
--- a/usr/src/lib/libzfs/common/libzfs_pool.c
+++ b/usr/src/lib/libzfs/common/libzfs_pool.c
@@ -28,6 +28,7 @@
* Copyright (c) 2017 Datto Inc.
* Copyright (c) 2017, Intel Corporation.
* Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Oxide Computer Company
*/
#include <ctype.h>
@@ -3960,17 +3961,70 @@ set_path(zpool_handle_t *zhp, nvlist_t *nv, const char *path)
}
/*
+ * This routine is 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.
+ */
+void
+zpool_vdev_refresh_path(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv)
+{
+ char *path = NULL;
+ char *newpath = NULL;
+ char *physpath = NULL;
+ char *devid = NULL;
+
+ if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) != 0) {
+ return;
+ }
+
+ if (nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
+ /*
+ * 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) {
+ newpath = devid_to_path(devid);
+ }
+
+ 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) {
+ /*
+ * No path update is required.
+ */
+ return;
+ }
+
+ set_path(zhp, nv, newpath);
+ fnvlist_add_string(nv, ZPOOL_CONFIG_PATH, newpath);
+
+ free(newpath);
+}
+
+/*
* 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.
+ * We will confirm that the path and name of the vdev are current, and update
+ * them if not. 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.
*/
@@ -4013,9 +4067,6 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
} 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
@@ -4030,42 +4081,12 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
goto after_open;
}
- if (nvlist_lookup_string(nv, ZPOOL_CONFIG_DEVID, &devid) == 0) {
- /*
- * 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) {
- newpath = devid_to_path(devid);
- }
-
- 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);
- }
+ /*
+ * Refresh the /dev path for this vdev if required, then ensure
+ * we're using the latest path value:
+ */
+ zpool_vdev_refresh_path(hdl, zhp, nv);
+ path = fnvlist_lookup_string(nv, ZPOOL_CONFIG_PATH);
if (name_flags & VDEV_NAME_FOLLOW_LINKS) {
char *rp = realpath(path, NULL);
diff --git a/usr/src/lib/libzfs/common/mapfile-vers b/usr/src/lib/libzfs/common/mapfile-vers
index 196751b44c..4c2c6e67fe 100644
--- a/usr/src/lib/libzfs/common/mapfile-vers
+++ b/usr/src/lib/libzfs/common/mapfile-vers
@@ -279,6 +279,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zpool_vdev_name;
zpool_vdev_offline;
zpool_vdev_online;
+ zpool_vdev_refresh_path;
zpool_vdev_remove;
zpool_vdev_remove_cancel;
zpool_vdev_split;
diff --git a/usr/src/lib/libzpool/Makefile.com b/usr/src/lib/libzpool/Makefile.com
index d52d56b1ff..47ff1d0b76 100644
--- a/usr/src/lib/libzpool/Makefile.com
+++ b/usr/src/lib/libzpool/Makefile.com
@@ -68,7 +68,7 @@ CSTD= $(CSTD_GNU99)
CFLAGS += $(CCGDEBUG) $(CCVERBOSE) $(CNOGLOBAL)
CFLAGS64 += $(CCGDEBUG) $(CCVERBOSE) $(CNOGLOBAL)
-LDLIBS += -lcmdutils -lumem -lavl -lnvpair -lz -lc -lsysevent -lmd \
+LDLIBS += -lcmdutils -lumem -lavl -lnvpair -lz -lc -lmd \
-lfakekernel -lzutil
NATIVE_LIBS += libz.so
CPPFLAGS.first = -I$(SRC)/lib/libfakekernel/common
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c
index 70d690d587..d390e39195 100644
--- a/usr/src/uts/common/fs/zfs/spa.c
+++ b/usr/src/uts/common/fs/zfs/spa.c
@@ -32,6 +32,7 @@
* Copyright (c) 2017, Intel Corporation.
* Copyright 2020 Joshua M. Clulow <josh@sysmgr.org>
* Copyright 2021 OmniOS Community Edition (OmniOSce) Association.
+ * Copyright 2022 Oxide Computer Company
*/
/*
@@ -5593,6 +5594,12 @@ spa_import_rootpool(char *devpath, char *devid, uint64_t pool_guid,
goto out;
}
+ /*
+ * The root disk may have been expanded while the system was offline.
+ * Kick off an async task to check for and handle expansion.
+ */
+ spa_async_request(spa, SPA_ASYNC_AUTOEXPAND);
+
error = 0;
out:
spa_config_enter(spa, SCL_ALL, FTAG, RW_WRITER);
@@ -7517,8 +7524,6 @@ spa_async_probe(spa_t *spa, vdev_t *vd)
static void
spa_async_autoexpand(spa_t *spa, vdev_t *vd)
{
- sysevent_id_t eid;
- nvlist_t *attr;
char *physpath;
if (!spa->spa_autoexpand)
@@ -7535,13 +7540,8 @@ spa_async_autoexpand(spa_t *spa, vdev_t *vd)
physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
(void) snprintf(physpath, MAXPATHLEN, "/devices%s", vd->vdev_physpath);
- VERIFY(nvlist_alloc(&attr, NV_UNIQUE_NAME, KM_SLEEP) == 0);
- VERIFY(nvlist_add_string(attr, DEV_PHYS_PATH, physpath) == 0);
-
- (void) ddi_log_sysevent(zfs_dip, SUNW_VENDOR, EC_DEV_STATUS,
- ESC_DEV_DLE, attr, &eid, DDI_SLEEP);
+ zfs_post_dle_sysevent(physpath);
- nvlist_free(attr);
kmem_free(physpath, MAXPATHLEN);
}
diff --git a/usr/src/uts/common/fs/zfs/spa_misc.c b/usr/src/uts/common/fs/zfs/spa_misc.c
index cb59eef824..6e834005a1 100644
--- a/usr/src/uts/common/fs/zfs/spa_misc.c
+++ b/usr/src/uts/common/fs/zfs/spa_misc.c
@@ -29,6 +29,7 @@
* Copyright 2019 Joyent, Inc.
* Copyright (c) 2017, Intel Corporation.
* Copyright 2020 Joyent, Inc.
+ * Copyright 2022 Oxide Computer Company
*/
#include <sys/zfs_context.h>
@@ -2598,3 +2599,44 @@ spa_suspend_async_destroy(spa_t *spa)
return (B_FALSE);
}
+
+/*
+ * Generate a LUN expansion event. This routine does not use
+ * ddi_log_sysevent() because that would require a dev_info_t, and we may not
+ * have one available.
+ */
+void
+zfs_post_dle_sysevent(const char *physpath)
+{
+#ifdef _KERNEL
+ sysevent_t *ev = sysevent_alloc(EC_DEV_STATUS, ESC_DEV_DLE,
+ SUNW_KERN_PUB "zfs", SE_SLEEP);
+ sysevent_attr_list_t *attr = NULL;
+ sysevent_id_t eid;
+
+ VERIFY(ev != NULL);
+
+ /*
+ * The only attribute is the /devices path of the expanding device:
+ */
+ sysevent_value_t value = {
+ .value_type = SE_DATA_TYPE_STRING,
+ .value = {
+ .sv_string = (char *)physpath,
+ },
+ };
+ if (sysevent_add_attr(&attr, DEV_PHYS_PATH, &value, SE_SLEEP) != 0) {
+ sysevent_free(ev);
+ return;
+ }
+
+ if (sysevent_attach_attributes(ev, attr) != 0) {
+ sysevent_free_attr(attr);
+ sysevent_free(ev);
+ return;
+ }
+
+ (void) log_sysevent(ev, SE_SLEEP, &eid);
+ sysevent_free(ev);
+#endif
+}
diff --git a/usr/src/uts/common/fs/zfs/sys/spa.h b/usr/src/uts/common/fs/zfs/sys/spa.h
index af8057be8f..b896d51577 100644
--- a/usr/src/uts/common/fs/zfs/sys/spa.h
+++ b/usr/src/uts/common/fs/zfs/sys/spa.h
@@ -1104,6 +1104,7 @@ extern sysevent_t *spa_event_create(spa_t *spa, vdev_t *vd, nvlist_t *hist_nvl,
const char *name);
extern void spa_event_post(sysevent_t *ev);
extern void spa_event_discard(sysevent_t *ev);
+extern void zfs_post_dle_sysevent(const char *);
#ifdef ZFS_DEBUG
#define dprintf_bp(bp, fmt, ...) do { \
diff --git a/usr/src/uts/common/fs/zfs/zvol.c b/usr/src/uts/common/fs/zfs/zvol.c
index 1de192f87f..2bb311d28d 100644
--- a/usr/src/uts/common/fs/zfs/zvol.c
+++ b/usr/src/uts/common/fs/zfs/zvol.c
@@ -813,20 +813,12 @@ zvol_update_live_volsize(zvol_state_t *zv, uint64_t volsize)
* Generate a LUN expansion event.
*/
if (error == 0) {
- sysevent_id_t eid;
- nvlist_t *attr;
char *physpath = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
(void) snprintf(physpath, MAXPATHLEN, "%s%u", ZVOL_PSEUDO_DEV,
zv->zv_minor);
- VERIFY(nvlist_alloc(&attr, NV_UNIQUE_NAME, KM_SLEEP) == 0);
- VERIFY(nvlist_add_string(attr, DEV_PHYS_PATH, physpath) == 0);
-
- (void) ddi_log_sysevent(zfs_dip, SUNW_VENDOR, EC_DEV_STATUS,
- ESC_DEV_DLE, attr, &eid, DDI_SLEEP);
-
- nvlist_free(attr);
+ zfs_post_dle_sysevent(physpath);
kmem_free(physpath, MAXPATHLEN);
}
return (error);