From 086105f4c4e6de3708459c56d3d3d3f3e8164596 Mon Sep 17 00:00:00 2001 From: Paul Dagnelie Date: Fri, 16 May 2025 10:19:04 -0700 Subject: [PATCH] Cause zpool scan resume commands to get logged in history Currently, commands that resume a scrub/errorscrub from a paused state don't get logged in the pool history. This is because resumes actually return ECANCELED, instead of 0. This causes the tsd code in the common ioctl logic to not think the ioctl succeeded, which causes the log_history ioctl to fail with EPERM. However, for resuming a scrub from a paused state, ECANCELED is success. There are two options for how to deal with this. The first is the one that I implemented here; I can't find a good reason for dmu_scan to return ECANCELED on resume instead of 0, so let's just not. The only place we check for the ECANCELED value is in zpool_scan, where we just convert it back to zero. However, I am aware that this is changing an ioctl interface, which I believe is a breaking change. I don't think it's an important change, but maybe there is someone who relies on it. The other option that could be implemented is to either allow ECANCELED specifically from dsl_scan in the common ioctl code, or add a generic facility to the common ioctl code that allows each command to specify whether or not success happened, regardless of the return values. I am open to feedback on which option people think would be better. Reviewed-by: Rob Norris Reviewed-by: Brian Behlendorf Reviewed-by: Alexander Motin Signed-off-by: Paul Dagnelie Sponsored-by: Klara, Inc. Sponsored-by: Wasabi Technology, Inc. Closes #17301 --- lib/libzfs/libzfs_pool.c | 5 +++++ module/zfs/dsl_scan.c | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 17677d0f8..6f8fb994f 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -2761,6 +2761,11 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd) * 1. we resumed a paused scrub. * 2. we resumed a paused error scrub. * 3. Error scrub is not run because of no error log. + * + * Note that we no longer return ECANCELED in case 1 or 2. However, in + * order to prevent problems where we have a newer userland than + * kernel, we keep this check in place. That prevents erroneous + * failures when an older kernel returns ECANCELED in those cases. */ if (err == ECANCELED && (func == POOL_SCAN_SCRUB || func == POOL_SCAN_ERRORSCRUB) && cmd == POOL_SCRUB_NORMAL) diff --git a/module/zfs/dsl_scan.c b/module/zfs/dsl_scan.c index cc8ce186d..e10b1a879 100644 --- a/module/zfs/dsl_scan.c +++ b/module/zfs/dsl_scan.c @@ -1021,7 +1021,7 @@ dsl_scan(dsl_pool_t *dp, pool_scan_func_t func, uint64_t txgstart, if (err == 0) { spa_event_notify(spa, NULL, NULL, ESC_ZFS_ERRORSCRUB_RESUME); - return (ECANCELED); + return (0); } return (SET_ERROR(err)); } @@ -1037,7 +1037,7 @@ dsl_scan(dsl_pool_t *dp, pool_scan_func_t func, uint64_t txgstart, POOL_SCRUB_NORMAL); if (err == 0) { spa_event_notify(spa, NULL, NULL, ESC_ZFS_SCRUB_RESUME); - return (SET_ERROR(ECANCELED)); + return (0); } return (SET_ERROR(err)); }