diff options
author | Joshua M. Clulow <josh@sysmgr.org> | 2022-11-08 12:54:43 -0800 |
---|---|---|
committer | Joshua M. Clulow <josh@sysmgr.org> | 2022-11-08 12:54:43 -0800 |
commit | b4fb003914e70b41d96dec8011864f6af1faf3ef (patch) | |
tree | f64867f9ae24b071f386b0c2fe24a47bd97bce79 | |
parent | 77c0a660417a046bfab6c8ef58d00c181c0264b3 (diff) | |
download | illumos-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.c | 8 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 2 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 115 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/mapfile-vers | 1 | ||||
-rw-r--r-- | usr/src/lib/libzpool/Makefile.com | 2 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 16 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa_misc.c | 42 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/spa.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zvol.c | 10 |
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); |