diff --git a/include/libzfs.h b/include/libzfs.h index 8d79fe69e..e2ec2d9bc 100644 --- a/include/libzfs.h +++ b/include/libzfs.h @@ -146,6 +146,7 @@ typedef enum zfs_error { EZFS_TRIMMING, /* currently trimming */ EZFS_NO_TRIM, /* no active trim */ EZFS_TRIM_NOTSUP, /* device does not support trim */ + EZFS_NO_RESILVER_DEFER, /* pool doesn't support resilver_defer */ EZFS_UNKNOWN } zfs_error_t; diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c index 6c797d06b..a6e26ebcd 100644 --- a/lib/libzfs/libzfs_pool.c +++ b/lib/libzfs/libzfs_pool.c @@ -2354,6 +2354,10 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd) (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot scrub %s"), zc.zc_name); } + } else if (func == POOL_SCAN_RESILVER) { + assert(cmd == POOL_SCRUB_NORMAL); + (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, + "cannot restart resilver on %s"), zc.zc_name); } else if (func == POOL_SCAN_NONE) { (void) snprintf(msg, sizeof (msg), dgettext(TEXT_DOMAIN, "cannot cancel scrubbing %s"), @@ -2381,6 +2385,8 @@ zpool_scan(zpool_handle_t *zhp, pool_scan_func_t func, pool_scrub_cmd_t cmd) } } else if (err == ENOENT) { return (zfs_error(hdl, EZFS_NO_SCRUB, msg)); + } else if (err == ENOTSUP && func == POOL_SCAN_RESILVER) { + return (zfs_error(hdl, EZFS_NO_RESILVER_DEFER, msg)); } else { return (zpool_standard_error(hdl, err, msg)); } diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index b988d8f31..19bb57ad4 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -300,6 +300,9 @@ libzfs_error_description(libzfs_handle_t *hdl) case EZFS_TRIM_NOTSUP: return (dgettext(TEXT_DOMAIN, "trim operations are not " "supported by this device")); + case EZFS_NO_RESILVER_DEFER: + return (dgettext(TEXT_DOMAIN, "this action requires the " + "resilver_defer feature")); case EZFS_UNKNOWN: return (dgettext(TEXT_DOMAIN, "unknown error")); default: diff --git a/man/man8/zpool.8 b/man/man8/zpool.8 index eb93d3bb3..971501d8d 100644 --- a/man/man8/zpool.8 +++ b/man/man8/zpool.8 @@ -2216,7 +2216,9 @@ again. .Xc Starts a resilver. If an existing resilver is already running it will be restarted from the beginning. Any drives that were scheduled for a deferred -resilver will be added to the new one. +resilver will be added to the new one. This requires the +.Sy resilver_defer +feature. .It Xo .Nm .Cm trim diff --git a/module/zfs/spa.c b/module/zfs/spa.c index c76163b6f..4d26d698e 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -7261,6 +7261,10 @@ spa_scan(spa_t *spa, pool_scan_func_t func) if (func >= POOL_SCAN_FUNCS || func == POOL_SCAN_NONE) return (SET_ERROR(ENOTSUP)); + if (func == POOL_SCAN_RESILVER && + !spa_feature_is_enabled(spa, SPA_FEATURE_RESILVER_DEFER)) + return (SET_ERROR(ENOTSUP)); + /* * If a resilver was requested, but there is no DTL on a * writeable leaf device, we have nothing to do. diff --git a/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/zpool_resilver_bad_args.ksh b/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/zpool_resilver_bad_args.ksh index 9d973bec7..abd514086 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/zpool_resilver_bad_args.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zpool_resilver/zpool_resilver_bad_args.ksh @@ -35,6 +35,8 @@ # 1. Create an array containing bad 'zpool reilver' parameters. # 2. For each element, execute the sub-command. # 3. Verify it returns an error. +# 4. Confirm the sub-command returns an error if the resilver_defer +# feature isn't active. # verify_runnable "global" @@ -45,6 +47,13 @@ set -A args "" "-?" "blah blah" "-%" "--?" "-*" "-=" \ "-A" "-B" "-C" "-D" "-E" "-F" "-G" "-H" "-I" "-J" "-K" "-L" \ "-M" "-N" "-O" "-P" "-Q" "-R" "-S" "-T" "-U" "-V" "-W" "-X" "-W" "-Z" +function cleanup +{ + log_must destroy_pool $TESTPOOL2 + log_must rm -f $TEST_BASE_DIR/zpool_resilver.dat +} + +log_onexit cleanup log_assert "Execute 'zpool resilver' using invalid parameters." @@ -55,4 +64,8 @@ while [[ $i -lt ${#args[*]} ]]; do ((i = i + 1)) done +log_must mkfile $MINVDEVSIZE $TEST_BASE_DIR/zpool_resilver.dat +log_must zpool create -d $TESTPOOL2 $TEST_BASE_DIR/zpool_resilver.dat +log_mustnot zpool resilver $TESTPOOL2 + log_pass "Badly formed 'zpool resilver' parameters fail as expected."