pool_iter_refresh: don't flag existing pools as refreshed

zpool_iter() passes the callback a new instance of zpool_handle_t each
time, so the existing handle in the pool_list AVL never actually gets a
refresh. Internally, that means its zpool_config is never updated, and
the old config is never moved to zpool_old_config. As a result,
print_iostat() never sees any updated config, and so repeats the first
line forever.

This is the simplest workaround: just don't mark existing pools as
refreshed. pool_list_refresh() will see this and refresh them.
The downside is a second call to ZFS_IOC_POOL_STATS for existing pools,
because zpool_iter() just called it for the handle we threw away.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Tony Hutter <hutter2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #17807
This commit is contained in:
Rob Norris 2025-10-01 09:20:08 +10:00 committed by Tony Hutter
parent 37d8d4619f
commit 4c84b77bc4

View File

@ -103,7 +103,6 @@ add_pool(zpool_handle_t *zhp, zpool_list_t *zlp)
new->zn_last_refresh = zlp->zl_last_refresh; new->zn_last_refresh = zlp->zl_last_refresh;
uu_avl_insert(zlp->zl_avl, new, idx); uu_avl_insert(zlp->zl_avl, new, idx);
} else { } else {
node->zn_last_refresh = zlp->zl_last_refresh;
zpool_close(zhp); zpool_close(zhp);
free(new); free(new);
return (-1); return (-1);
@ -203,31 +202,23 @@ pool_list_refresh(zpool_list_t *zlp)
return (navail); return (navail);
} }
/* /* Search for any new pools and add them to the list. */
* Search for any new pools and add them to the list. zpool_iter()
* will call zpool_refresh_stats() as part of its work, so this has
* the side effect of updating all active handles.
*/
(void) zpool_iter(g_zfs, add_pool_cb, zlp); (void) zpool_iter(g_zfs, add_pool_cb, zlp);
/* /* Walk the list of existing pools, and update or remove them. */
* Walk the list for any that weren't refreshed, and update and remove
* them. It's not enough to just skip available ones, as zpool_iter()
* won't update them, so they'll still appear active in our list.
*/
zpool_node_t *node, *next; zpool_node_t *node, *next;
for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next) { for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next) {
next = uu_avl_next(zlp->zl_avl, node); next = uu_avl_next(zlp->zl_avl, node);
/* /*
* Skip any that were refreshed and are online; they're already * Skip any that were refreshed and are online; they were added
* handled. * by zpool_iter() and are already up to date.
*/ */
if (node->zn_last_refresh == zlp->zl_last_refresh && if (node->zn_last_refresh == zlp->zl_last_refresh &&
zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL) zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL)
continue; continue;
/* Do the refresh ourselves, just in case. */ /* Refresh and remove if necessary. */
boolean_t missing; boolean_t missing;
zpool_refresh_stats(node->zn_handle, &missing); zpool_refresh_stats(node->zn_handle, &missing);
if (missing) { if (missing) {