Skip to content

Commit

Permalink
zed: Fix config_sync autoexpand flood
Browse files Browse the repository at this point in the history
Users were seeing floods of `config_sync` events when autoexpand was
enabled.  This happened because all "disk status change" udev events
invoke the autoexpand codepath, which calls zpool_relabel_disk(),
which in turn cause another "disk status change" event to happen,
in a feedback loop.  Note that "disk status change" happens every time
a user calls close() on a block device.

This commit breaks the feedback loop by only allowing an autoexpand
to happen if the disk actually changed size.

Fixes: openzfs#7132
Fixes: openzfs#7366

Signed-off-by: Tony Hutter <hutter2@llnl.gov>
  • Loading branch information
tonyhutter committed Aug 3, 2022
1 parent 2f157cb commit 174ae18
Showing 1 changed file with 81 additions and 8 deletions.
89 changes: 81 additions & 8 deletions cmd/zed/agents/zfs_mod.c
Original file line number Diff line number Diff line change
Expand Up @@ -894,14 +894,55 @@ zfs_deliver_check(nvlist_t *nvl)
return (0);
}

/*
* Given a path to a vdev, lookup the vdev's physical size from its
* config nvlist.
*
* Returns the vdev's physical size in bytes on success, 0 on error.
*/
static uint64_t
vdev_size_from_config(zpool_handle_t *zhp, const char *vdev_path)
{
nvlist_t *nvl = NULL;
boolean_t avail_spare, l2cache, log;
vdev_stat_t *vs = NULL;
uint_t c;

nvl = zpool_find_vdev(zhp, vdev_path, &avail_spare, &l2cache, &log);
if (!nvl)
return 0;

verify(nvlist_lookup_uint64_array(nvl, ZPOOL_CONFIG_VDEV_STATS,
(uint64_t **)&vs, &c) == 0);
if (!vs) {
zed_log_msg(LOG_INFO, "%s: no nvlist for '%s'",
__func__, vdev_path);
return 0;
}

return vs->vs_pspace;
}

static int
zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
{
char *devname = data;
boolean_t avail_spare, l2cache;
nvlist_t *udev_nvl = data;
nvlist_t *tgt;
int error;

char *tmp_devname, devname[MAXPATHLEN];
uint64_t guid;

if (nvlist_lookup_uint64(udev_nvl, ZFS_EV_VDEV_GUID, &guid) == 0) {
sprintf(devname, "%llu", (u_longlong_t)guid);
} else if (nvlist_lookup_string(udev_nvl, DEV_PHYS_PATH, &tmp_devname) == 0) {
strlcpy(devname, tmp_devname, MAXPATHLEN);
zfs_append_partition(devname, MAXPATHLEN);
} else {
zed_log_msg(LOG_INFO, "%s: no guid or physpath", __func__);
}

zed_log_msg(LOG_INFO, "zfsdle_vdev_online: searching for '%s' in '%s'",
devname, zpool_get_name(zhp));

Expand Down Expand Up @@ -953,12 +994,44 @@ zfsdle_vdev_online(zpool_handle_t *zhp, void *data)
vdev_state_t newstate;

if (zpool_get_state(zhp) != POOL_STATE_UNAVAIL) {
error = zpool_vdev_online(zhp, fullpath, 0,
&newstate);
zed_log_msg(LOG_INFO, "zfsdle_vdev_online: "
"setting device '%s' to ONLINE state "
"in pool '%s': %d", fullpath,
zpool_get_name(zhp), error);
/*
* If this disk size has not changed, then there's
* no need to do an autoexpand. To check we look
* at the disk's size in its config, and compare
* it to the disk size that udev is reporting.
*/
uint64_t udev_size = 0, conf_size = 0;

/*
* Earlier we put udev's reported disk size
* into a nvlist. Extract it here.
*/
if (nvlist_lookup_uint64(udev_nvl, DEV_SIZE,
&udev_size) != 0) {
/*
* No DEV_SIZE - set udev_size to 0, which
* will in turn attempt the
* zpool_vdev_online()
*/
udev_size = 0;
}

conf_size = vdev_size_from_config(zhp, fullpath);

/*
* Only attempt an autoexpand if the drive size
* changed.
*/
if (conf_size != udev_size) {
error = zpool_vdev_online(zhp, fullpath, 0,
&newstate);
zed_log_msg(LOG_INFO, "%s: autoexpand "
"setting '%s' to ONLINE state in pool "
"'%s': %d (was %llu bytes, now %llu "
"bytes)", __func__, fullpath,
zpool_get_name(zhp), error, conf_size,
udev_size);
}
}
}
zpool_close(zhp);
Expand Down Expand Up @@ -989,7 +1062,7 @@ zfs_deliver_dle(nvlist_t *nvl)
zed_log_msg(LOG_INFO, "zfs_deliver_dle: no guid or physpath");
}

if (zpool_iter(g_zfshdl, zfsdle_vdev_online, name) != 1) {
if (zpool_iter(g_zfshdl, zfsdle_vdev_online, nvl) != 1) {
zed_log_msg(LOG_INFO, "zfs_deliver_dle: device '%s' not "
"found", name);
return (1);
Expand Down

0 comments on commit 174ae18

Please sign in to comment.